码迷,mamicode.com
首页 > 其他好文 > 详细

P3119 [USACO15JAN]草鉴定Grass Cownoisseur

时间:2018-11-06 11:17:53      阅读:197      评论:0      收藏:0      [点我收藏+]

标签:set   else   etc   head   一个   empty   ems   turn   bool   

缩点+分层图+最长路

通过这道题,我再次体会到了分层图的强大之处。

首先可以发现,那些属于同一个强连通分量的点是可以直接看成一个点的,因为他们可以互相访问。

那么直接缩点,可以建出一个新图,就得到了一个DAG。

这道题最难的地方就是在于一次逆向行走。

遇到这种题目,我们直接使用分层图解决。

既然只能逆向走一次,那么我们建立2层图,每层图内部正常连边,上面一层图连一条代表“逆向行走”的有向边边来到下一层图。

那么求出第一层1所属强联通分量的点 到 第二层1所属强联通分量的点 之间的最长路,就是我们的答案了。

注意:这里没有边权而是点权,但是起点的点权和终点的点权只能够算一次,因为每个草场只能访问一次。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
const int maxn = 100005;
struct Edges
{
    int next, to;
};
Edges e[maxn];
int head[maxn], tot;

int dfn[maxn], low[maxn], dtot;
int col[maxn], ctot;
int size[maxn * 2];
bool vis[maxn * 2];
Edges e2[maxn * 3];
int head2[maxn * 2], tot2;
int dist[maxn * 2];
int n, m;

std::stack<int> sta;
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > ‘9‘ || ch < ‘0‘){ if(ch == ‘-‘) s = -1; ch = getchar(); }
    while(ch >= ‘0‘ && ch <= ‘9‘) ans = ans * 10 + ch - ‘0‘, ch = getchar();
    return s * ans;
}
void link(int u, int v)
{
    e[++tot] = (Edges){head[u], v};
    head[u] = tot;
}
void link2(int u, int v)
{
    e2[++tot2] = (Edges){head2[u], v};
    head2[u] = tot2;
}
void tarjan(int u)
{
    dfn[u] = low[u] = ++dtot;
    sta.push(u); vis[u] = true;
    for(int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        if(!dfn[v])
        {
            tarjan(v); low[u] = std::min(low[u], low[v]);
        }
        else if(vis[v]) low[u] = std::min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u])
    {
        ctot++;
        while(sta.top() != u)
        {
            int x = sta.top(); sta.pop(); vis[x] = false;
            col[x] = ctot; size[ctot]++;
        }
        int x = sta.top(); sta.pop(); vis[x] = false;
        col[x] = ctot; size[ctot]++;
    }
}
int spfa(int s, int t)
{
    std::queue<int> q;
    memset(vis, false, sizeof vis);
    dist[s] = 0; q.push(s); vis[s] = true;
    while(!q.empty())
    {
        int u = q.front(); q.pop(); vis[u] = false;
        for(int i = head2[u]; i; i = e2[i].next)
        {
            int v = e2[i].to;
            if(dist[u] + size[v] > dist[v])
            {
                dist[v] = dist[u] + size[v];
                if(!vis[v])
                {
                    q.push(v); vis[v] = true;
                }
            }
        }
    }
    return dist[t];
}
int main()
{
    n = read(), m = read();
    while(m--)
    {
        int u = read(), v = read();
        link(u, v);
    }
    for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
    for(int u = 1; u <= n; u++)
    {
        for(int i = head[u]; i; i = e[i].next)
        {
            int v = e[i].to;
            if(col[u] != col[v])
            {
                link2(col[u], col[v]);
                link2(col[u] + ctot, col[v] + ctot);
                link2(col[v], col[u] + ctot);
            }
        }
    }
    for(int i = 1; i <= ctot; i++) size[i + ctot] = size[i];
    printf("%d\n", spfa(col[1], ctot + col[1]));
    return 0;
}

P3119 [USACO15JAN]草鉴定Grass Cownoisseur

标签:set   else   etc   head   一个   empty   ems   turn   bool   

原文地址:https://www.cnblogs.com/Garen-Wang/p/9913189.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!