hiho详解链接:http://hihocoder.com/contest/hiho54/problem/1
强连通分量的定义:对于有向图上的2个点a,b,若存在一条从a到b的路径,也存在一条从b到a的路径,那么称a,b是强连通的。对于有向图上的一个子图,若子图内任意点对(a,b)都是满足强连通,则称该子图为强连通子图。非强连通图有向图的极大强连通子图,称为强连通分量。特别的,任意一个和其他点都不相连的单个点也是一个强连通分量。
需要特别注意的是,强连通一般是对于有向图而言的。
tarjan求强连通分量的模板:
void tarjan(int u)
{
dfs_pos[u] = low[u] = ++jilu;
sta.push(u);//每个节点进入时先压栈
vis[u] = -1;//vis = -1表示已经在栈中了,0表示从未被访问过,1表示该点已经被标记成一个强连通分量了
int v;
for(int i = head[u];~i;i = e[i].nex)
{
v = e[i].v;
if(vis[v] == 0){//对于从未被访问过的点,继续tarjan深搜
tarjan(v);
low[u] = min(low[v],low[u]);
}else if(vis[v] == -1)//对于已经访问过的点,若不是直接相连的父亲而是祖先则更新
low[u] = min(low[v],low[u]);
}
if(dfs_pos[u] == low[u])//dfs序和最近父亲相等,将栈中一直到u的点都弹出并标记为同一个强连通分量
{
while(!sta.empty())
{
int temp = sta.top();
mark[temp] = u;
sta.pop();
if(temp == u)break;
}
vis[u] = 1;
}
}
hiho的原题题解:
数据中会有重边,这样的话在我原来的拓扑找最大的时候会有问题。。。很坑。。。后来改成dfs求就对了
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
const int maxn = 250005;
struct ppp
{
int v,nex;
}e[maxn],ee[maxn];
int head[maxn / 10],tole,n,m,vis[maxn / 10],jilu;
int w[maxn / 10];
int dfs_pos[maxn / 10],low[maxn / 10];
stack<int> sta;
int mark[maxn / 10];
void make_edge(int u,int v)
{
e[tole].v = v;e[tole].nex = head[u];head[u] = tole++;
}
void tarjan(int u)
{
dfs_pos[u] = low[u] = ++jilu;
sta.push(u);//每个节点进入时先压栈
vis[u] = -1;//vis = -1表示已经在栈中了,0表示从未被访问过,1表示该点已经被标记成一个强连通分量了
int v;
for(int i = head[u];~i;i = e[i].nex)
{
v = e[i].v;
if(vis[v] == 0){//对于从未被访问过的点,继续tarjan深搜
tarjan(v);
low[u] = min(low[v],low[u]);
}else if(vis[v] == -1)//对于已经访问过的点,若不是直接相连的父亲而是祖先则更新
low[u] = min(low[v],low[u]);
}
if(dfs_pos[u] == low[u])//dfs序和最近父亲相等,将栈中一直到u的点都弹出并标记为同一个强连通分量
{
while(!sta.empty())
{
int temp = sta.top();
mark[temp] = u;
sta.pop();
if(temp == u)break;
}
vis[u] = 1;
}
}
int in[maxn / 10];
vector<int> vec[maxn / 10];
int maxx;
void dfss(int u,int fa,int haha)
{
int v;
maxx = max(haha,maxx);
for(int i = 0;i < vec[u].size();i++)
{
v = vec[u][i];
if(v == fa)continue;
dfss(v,u,haha + w[v]);
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
int a,b;
mem(head,-1);tole = 0;jilu = 0;
mem(vis,0);
while(!sta.empty())sta.pop();
for(int i = 1;i <= n;i++)cin>>w[i];
for(int i = 0;i < m;i++)
{
scanf("%d%d",&a,&b);
make_edge(a,b);
}
mark[1] = 1;
for(int i = 1;i <= n;i++)
if(!vis[i])
tarjan(i);
for(int i = 1;i <= n;i++)
if(mark[i] != i)
w[mark[i]] += w[i];
for(int i = 1;i <= n;i++)vec[i].clear(),in[i] = 0;
for(int i = 1;i <= n;i++)
for(int j = head[i];~j;j = e[j].nex)
if(mark[i] != mark[e[j].v])
{
vec[mark[i]].push_back(mark[e[j].v]);
in[e[j].v]++;
}
maxx = w[1];
dfss(1,-1,w[1]);
cout<<maxx<<endl;
}
}