标签: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