hdu 1269
判断是否存在一个强连通
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 #include<vector> 7 using namespace std; 8 9 const int maxn = 10005; 10 vector<int> g[maxn]; 11 stack<int> S; 12 13 int n,m; 14 int sccno[maxn],low[maxn],pre[maxn]; 15 int scc_cnt,dfs_clock; 16 17 void init(){ 18 while(!S.empty()) S.pop(); 19 for(int i = 1;i <= n;i++) g[i].clear(); 20 scc_cnt = dfs_clock = 0; 21 memset(sccno,0,sizeof(sccno)); 22 memset(low,0,sizeof(low)); 23 memset(pre,0,sizeof(pre)); 24 } 25 26 void dfs(int u){ 27 low[u] = pre[u] = ++dfs_clock; 28 S.push(u); 29 for(int i = 0;i < g[u].size();i++){ 30 int v = g[u][i]; 31 if(!pre[v]){ 32 dfs(v); 33 low[u] = min(low[v],low[u]); 34 } 35 else if(!sccno[v]) low[u] = min(low[u],pre[v]); 36 } 37 if(low[u] == pre[u]){ 38 scc_cnt++; 39 for(;;){ 40 int x = S.top();S.pop(); 41 sccno[x] = scc_cnt; 42 if(x == u) break; 43 } 44 } 45 } 46 47 void find_scc(){ 48 for(int i = 1;i <= n;i++){ 49 if(!pre[i]) dfs(i); 50 } 51 if(scc_cnt == 1) printf("Yes "); 52 else printf("No "); 53 } 54 55 int main(){ 56 while(scanf("%d %d",&n,&m) != EOF && (n ||m)){ 57 init(); 58 for(int i = 0;i < m;i++){ 59 int u,v; 60 scanf("%d %d",&u,&v); 61 g[u].push_back(v); 62 } 63 find_scc(); 64 } 65 return 0; 66 }
la 4287
白书上的例题
给一张图,问最少需要添加多少条边变成强连通
先求一遍强连通,然后把每一个强连通分量缩成一个点,再扫一遍边,如果发现一条边的两端u,v属于不同的强连通分量,如果是u--->v,那么in[scc[v]]++,out[scc[u]++;
最后统计入度为0的强连通分量个数a,出度为0的b,max(a,b)即为添加的最少边数
因为对于一个强连通,每一个点的入度至少为1.出度也至少为1,添加max(a,b)条边,能够满足这个条件
----不知道为什么用vector存图写的wa了,换成邻接表就过了
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 using namespace std; 7 8 const int maxn = 20005; 9 int first[maxn]; 10 int low[maxn],pre[maxn],sc[maxn]; 11 int din[maxn],dout[maxn]; 12 int n,m; 13 int ecnt,scnt,dfs_clock; 14 stack<int> S; 15 16 struct Edge{ 17 int v,next; 18 }e[3*maxn]; 19 20 void init(){ 21 ecnt = 0; 22 memset(first,-1,sizeof(first)); 23 memset(din,0,sizeof(din)); 24 memset(dout,0,sizeof(dout)); 25 } 26 27 void addedges(int u,int v){ 28 e[ecnt].v = v; 29 e[ecnt].next = first[u]; 30 first[u] = ecnt++; 31 } 32 33 void dfs(int u){ 34 low[u] = pre[u] = ++dfs_clock; 35 S.push(u); 36 for(int i = first[u];~i;i = e[i].next){ 37 int v = e[i].v; 38 if(!pre[v]){ 39 dfs(v); 40 low[u] = min(low[u],low[v]); 41 } 42 else if(!sc[v]) low[u] = min(low[u],pre[v]); 43 } 44 if(pre[u] == low[u]){ 45 scnt++; 46 for(;;){ 47 int x = S.top();S.pop(); 48 sc[x] = scnt; 49 if(x == u) break; 50 } 51 } 52 } 53 54 void find_scc(){ 55 while(!S.empty()) S.pop(); 56 memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); 57 memset(sc,0,sizeof(sc)); 58 dfs_clock = scnt = 0; 59 for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i); 60 } 61 62 int main(){ 63 int T; 64 scanf("%d",&T); 65 while(T--){ 66 scanf("%d %d",&n,&m); 67 init(); 68 for(int i = 1;i <= m;i++){ 69 int u,v; 70 scanf("%d %d",&u,&v); 71 addedges(u,v); 72 } 73 find_scc(); 74 if(scnt == 1){ 75 printf("0 "); 76 continue; 77 } 78 for(int u = 1;u <= n;u++){ 79 for(int i = first[u];~i;i = e[i].next){ 80 int v = e[i].v; 81 if(sc[u] != sc[v]){ 82 din[sc[v]]++; 83 dout[sc[u]]++; 84 } 85 } 86 } 87 88 // printf("scnt = %d ",scnt); 89 // for(int i = 1;i <= scnt;i++) 90 // printf("din[%d] = %d dout[%d] = %d ",i,din[i],i,dout[i]); 91 92 int a = 0,b = 0; 93 for(int i = 1;i <= scnt;i++){ 94 if(din[i] == 0) a++; 95 if(dout[i] == 0) b++; 96 } 97 printf("%d ",max(a,b)); 98 } 99 return 0; 100 }
uva 11324
先求一遍强连通,再缩点,每个点的权值为这个强连通分量里面的节点个数,就可以转化成DAG上的动态规划来做了
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 #include<vector> 7 using namespace std; 8 9 const int maxn = 5005; 10 int n,m; 11 int first[maxn]; 12 int sc[maxn],scn[maxn],low[maxn],pre[maxn]; 13 int scnt,ecnt,dfs_clock; 14 int dp[maxn]; 15 16 int first1[maxn]; 17 int ecnt1; 18 19 struct Edge{ 20 int v,next; 21 }e[maxn*10]; 22 23 Edge e1[maxn*10]; 24 25 stack<int> S; 26 27 void init(){ 28 ecnt = ecnt1 = 0; 29 memset(first,-1,sizeof(first)); 30 memset(first1,-1,sizeof(first1)); 31 memset(dp,0,sizeof(dp)); 32 } 33 34 void addedges(int u,int v){ 35 e[ecnt].v = v; 36 e[ecnt].next = first[u]; 37 first[u] = ecnt++; 38 } 39 40 void addedges1(int u,int v){ 41 e1[ecnt1].v = v; 42 e1[ecnt1].next = first1[u]; 43 first1[u] = ecnt1++; 44 } 45 46 void dfs(int u){ 47 low[u] = pre[u] = ++dfs_clock; 48 S.push(u); 49 for(int i = first[u];~i;i = e[i].next){ 50 int v = e[i].v; 51 if(!pre[v]){ 52 dfs(v); 53 low[u] = min(low[u],low[v]); 54 } 55 else if(!sc[v]) low[u] = min(low[u],pre[v]); 56 } 57 if(pre[u] == low[u]){ 58 scnt++; 59 for(;;){ 60 int x = S.top();S.pop(); 61 sc[x] = scnt; 62 scn[scnt]++; 63 if(x == u) break; 64 } 65 } 66 } 67 68 void find_scc(){ 69 while(!S.empty()) S.pop(); 70 scnt = dfs_clock = 0; 71 memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); 72 memset(sc,0,sizeof(sc));memset(scn,0,sizeof(scn)); 73 74 for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i); 75 } 76 77 int solve(int p){ 78 if(dp[p]) return dp[p]; 79 for(int i = first1[p];~i;i = e1[i].next){ 80 int v = e1[i].v; 81 dp[p] = max(dp[p],solve(v)); 82 } 83 return dp[p] = dp[p] + scn[p]; 84 } 85 86 87 int main(){ 88 int T; 89 scanf("%d",&T); 90 while(T--){ 91 init(); 92 scanf("%d %d",&n,&m); 93 for(int i = 0;i < m;i++ ){ 94 int u,v; 95 scanf("%d %d",&u,&v); 96 addedges(u,v); 97 } 98 find_scc(); 99 100 for(int u = 1;u <= n;u++){ 101 for(int i = first[u];~i;i = e[i].next){ 102 int v = e[i].v; 103 if(sc[u] != sc[v]) addedges1(sc[u],sc[v]); 104 } 105 } 106 107 108 int ans = 0; 109 for(int i = 1;i <= scnt;i++) ans = max(ans,solve(i)); 110 printf("%d ",ans); 111 } 112 return 0; 113 }
poj 1236
和 la 4287一样,再多一个问题,就是输出入度为0的强连通分量有多少个
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 using namespace std; 7 8 const int maxn = 1005; 9 int n; 10 stack<int> S; 11 12 int first[maxn]; 13 int low[maxn],pre[maxn],sc[maxn]; 14 int scnt,ecnt,dfs_clock; 15 int din[maxn],dout[maxn]; 16 17 struct Edge{ 18 int v,next; 19 }e[maxn*50]; 20 21 void init(){ 22 ecnt = 0; 23 memset(first,-1,sizeof(first)); 24 memset(din,0,sizeof(din)); 25 memset(dout,0,sizeof(dout)); 26 } 27 28 void addedges(int u,int v){ 29 e[ecnt].v = v; 30 e[ecnt].next = first[u]; 31 first[u] = ecnt++; 32 } 33 34 void dfs(int u){ 35 low[u] = pre[u] = ++dfs_clock; 36 S.push(u); 37 for(int i = first[u];~i;i = e[i].next){ 38 int v = e[i].v; 39 if(!pre[v]){ 40 dfs(v); 41 low[u] = min(low[u],low[v]); 42 } 43 else if(!sc[v]) low[u] = min(low[u],pre[v]); 44 } 45 46 if(pre[u] == low[u]){ 47 scnt++; 48 for(;;){ 49 int x = S.top();S.pop(); 50 sc[x] = scnt; 51 if(x == u) break; 52 } 53 } 54 } 55 56 void find_scc(){ 57 scnt = dfs_clock = 0; 58 memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); 59 memset(sc,0,sizeof(sc)); 60 for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i); 61 } 62 int main(){ 63 while(scanf("%d",&n) != EOF){ 64 init(); 65 for(int i = 1;i <= n;i++){ 66 int a; 67 while(scanf("%d",&a) != EOF && a){ 68 addedges(i,a); 69 } 70 } 71 find_scc(); 72 if(scnt == 1){ 73 printf("1 0 "); 74 continue; 75 } 76 77 for(int u = 1;u <= n;u++){ 78 for(int i = first[u];~i;i = e[i].next){ 79 int v = e[i].v; 80 if(sc[u] != sc[v]){ 81 din[sc[v]]++; 82 dout[sc[u]]++; 83 } 84 } 85 } 86 87 int c1 = 0,c2 = 0; 88 for(int i = 1;i <= scnt;i++){ 89 if(din[i] == 0) c1++; 90 if(dout[i] == 0) c2++; 91 } 92 printf("%d %d ",c1,max(c1,c2)); 93 } 94 return 0; 95 }
zoj 2588
无向图求桥,注意一下重边
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 using namespace std; 7 8 const int maxn = 50005; 9 int n,m; 10 int first[maxn]; 11 int low[maxn],pre[maxn],ans[maxn]; 12 13 int ecnt,cnt,dfs_clock; 14 15 struct Edge{ 16 int v,next,id; 17 int tag; 18 }e[maxn*10]; 19 20 void init(){ 21 ecnt = cnt = dfs_clock = 0; 22 memset(first,-1,sizeof(first)); 23 memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); 24 memset(ans,0,sizeof(ans)); 25 } 26 27 void addedges(int u,int v,int id){ 28 int i; 29 for( i = first[u];~i;i = e[i].next){ 30 if(e[i].v == v) break; 31 } 32 if(i != -1){ 33 e[i].tag = 1;//如果存边的时候发现有重边,则这条边不会成为桥,标记出来,不用再储存这条边 34 return; 35 } 36 e[ecnt].tag = 0; 37 e[ecnt].v = v; 38 e[ecnt].next = first[u]; 39 e[ecnt].id = id; 40 first[u] = ecnt++; 41 } 42 43 void tarjan(int u,int fa){ 44 low[u] = pre[u] = ++dfs_clock; 45 for(int i = first[u];~i;i = e[i].next){ 46 int v = e[i].v; 47 if(v == fa) continue; 48 if(!pre[v]){ 49 tarjan(v,u); 50 low[u] = min(low[u],low[v]); 51 if(low[v] > pre[u] && e[i].tag == 0){ 52 ans[cnt++] = e[i].id; 53 } 54 } 55 else low[u] = min(low[u],pre[v]); 56 } 57 } 58 59 int main(){ 60 int T; 61 scanf("%d",&T); 62 while(T--){ 63 init(); 64 scanf("%d %d",&n,&m); 65 for(int i = 1;i <= m;i++){ 66 int u,v; 67 scanf("%d %d",&u,&v); 68 addedges(u,v,i);addedges(v,u,i); 69 } 70 tarjan(1,0); 71 printf("%d ",cnt); 72 if(cnt){ 73 sort(ans,ans+cnt); 74 printf("%d",ans[0]); 75 for(int i = 1;i < cnt;i++) printf(" %d",ans[i]); 76 printf(" "); 77 } 78 if(T) printf(" "); 79 } 80 return 0; 81 }
poj 3352 边双连通
给定一张无向图,使得删掉任意一条边之后,整张图还是连通的至少需要添加多少条边
先用tarjan()求一下每个节点的low,用low的值来缩点,因为在同一个连通分量上的节点的low值都是相同的,
无向图的度数的定义是,这个节点连有几条边,它的度数就是几
然后再扫一遍边,如果这条边的两端的low值不同,则d[low[v]]++,d[low[u]]不用++,因为是无向图,在存边的时候就正向反向的边都存了
所以只需要加一个
然后求出度数为1的块有ans个
那么加(ans+1)/2条边就可以了
是因为将度数为1的块两两连接起来,即为(ans+1)/2
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 8 const int maxn = 1005; 9 int n,m; 10 int d[maxn]; 11 int low[maxn],pre[maxn]; 12 int first[maxn]; 13 int ecnt,dfs_clock; 14 15 struct Edge{ 16 int v,next; 17 }e[10*maxn]; 18 19 void init(){ 20 ecnt = dfs_clock = 0; 21 memset(first,-1,sizeof(first)); 22 memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); 23 memset(d,0,sizeof(d)); 24 } 25 26 void addedges(int u,int v){ 27 e[ecnt].v = v; 28 e[ecnt].next = first[u]; 29 first[u] = ecnt++; 30 } 31 32 void tarjan(int u,int fa){ 33 low[u] = pre[u] = ++dfs_clock; 34 for(int i = first[u];~i;i = e[i].next){ 35 int v = e[i].v; 36 if(v == fa) continue; 37 if(!pre[v]){ 38 tarjan(v,u); 39 low[u] = min(low[u],low[v]); 40 } 41 else if(v != fa) low[u] = min(low[u],pre[v]); 42 } 43 } 44 45 int main(){ 46 while(scanf("%d %d",&n,&m) != EOF){ 47 init(); 48 for(int i = 1;i <= m;i++){ 49 int u,v; 50 scanf("%d %d",&u,&v); 51 addedges(u,v);addedges(v,u); 52 } 53 tarjan(1,-1); 54 55 // for(int i = 1;i <= n;i++) 56 // printf("pre[%d] = %d low[%d] = %d ",i,pre[i],i,low[i]); 57 58 for(int u = 1;u <= n;u++){ 59 for(int i = first[u];~i;i = e[i].next){ 60 int v = e[i].v; 61 if(low[u] != low[v]) d[low[v]]++; 62 } 63 } 64 65 // for(int i = 1;i <= n;i++) 66 // printf("d[%d] = %d ",i,d[i]); 67 68 int ans = 0; 69 for(int i = 1;i <= n;i++) if(d[i]== 1) ans++; 70 printf("%d ",(ans+1)/2); 71 } 72 return 0; 73 }
hdu 1827
先求一遍强连通,然后缩点
找入度为0的点就是需要传递消息的块,找出这个块里面花费最少的,再累加起来
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 using namespace std; 7 8 const int maxn = 1005; 9 const int INF = 1000000005; 10 int first[maxn]; 11 int n,m; 12 int scnt,dfs_clock,ecnt; 13 int low[maxn],pre[maxn],sc[maxn]; 14 int in[maxn],a[maxn]; 15 int cost[maxn]; 16 stack<int> S; 17 18 struct Edge{ 19 int v,next; 20 }e[10*maxn]; 21 22 void init(){ 23 ecnt = 0; 24 memset(first,-1,sizeof(first)); 25 memset(in,0,sizeof(in)); 26 memset(a,0,sizeof(a)); 27 for(int i = 1;i <= n;i++) cost[i] = INF; 28 } 29 30 void addedges(int u,int v){ 31 e[ecnt].v = v; 32 e[ecnt].next = first[u]; 33 first[u] = ecnt++; 34 } 35 36 void dfs(int u){ 37 low[u] = pre[u] = ++dfs_clock; 38 S.push(u); 39 for(int i = first[u];~i;i = e[i].next){ 40 int v = e[i].v; 41 if(!pre[v]){ 42 dfs(v); 43 low[u] = min(low[u],low[v]); 44 } 45 else if(!sc[v]) low[u] = min(low[u],pre[v]); 46 } 47 if(pre[u] == low[u]){ 48 scnt++; 49 for(;;){ 50 int x = S.top();S.pop(); 51 sc[x] = scnt; 52 if(x == u) break; 53 } 54 } 55 } 56 57 void find_scc(){ 58 scnt = dfs_clock = 0; 59 memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); 60 memset(sc,0,sizeof(sc)); 61 62 for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i); 63 } 64 65 int main(){ 66 while(scanf("%d %d",&n,&m) != EOF){ 67 init(); 68 for(int i = 1;i <= n;i++) scanf("%d",&a[i]); 69 for(int i = 0;i < m;i++){ 70 int u,v; 71 scanf("%d %d",&u,&v); 72 addedges(u,v); 73 } 74 find_scc(); 75 for(int u = 1;u <= n;u++){ 76 for(int i = first[u];~i;i = e[i].next){ 77 int v = e[i].v; 78 if(sc[u] != sc[v]) in[sc[v]]++; 79 } 80 } 81 82 for(int i = 1;i <= n;i++){ 83 if(in[sc[i]] == 0) cost[sc[i]] = min(cost[sc[i]],a[i]); 84 } 85 86 int ans = 0,res = 0; 87 for(int i = 1;i <= scnt;i++){ 88 if(in[i] == 0) ans += cost[i],res++; 89 } 90 printf("%d %d ",res,ans); 91 } 92 return 0; 93 }
hdu 3072
给定一个定点,到其他所有点的花费最小
先求一遍强连通,再缩点,更新不同的连通块之间的最小的花费,如果某一块的d[i] = INF,说明其他的块都不能到达它
则说明它的入度为0,为给定的那个定点
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 using namespace std; 7 8 const int maxn = 50005; 9 const int INF = 1000000005; 10 typedef long long LL; 11 int first[maxn]; 12 int n,m; 13 int scnt,dfs_clock,ecnt; 14 int low[maxn],pre[maxn],sc[maxn]; 15 int in[maxn]; 16 int d[maxn]; 17 stack<int> S; 18 19 struct Edge{ 20 int v,next,w; 21 }e[10*maxn]; 22 23 void init(){ 24 ecnt = 0; 25 memset(first,-1,sizeof(first)); 26 memset(in,0,sizeof(in)); 27 for(int i = 1;i <= n;i++) d[i] = INF; 28 } 29 30 void addedges(int u,int v,int w){ 31 e[ecnt].v = v; 32 e[ecnt].w = w; 33 e[ecnt].next = first[u]; 34 first[u] = ecnt++; 35 } 36 37 void dfs(int u){ 38 low[u] = pre[u] = ++dfs_clock; 39 S.push(u); 40 for(int i = first[u];~i;i = e[i].next){ 41 int v = e[i].v; 42 if(!pre[v]){ 43 dfs(v); 44 low[u] = min(low[u],low[v]); 45 } 46 else if(!sc[v]) low[u] = min(low[u],pre[v]); 47 } 48 if(pre[u] == low[u]){ 49 scnt++; 50 for(;;){ 51 int x = S.top();S.pop(); 52 sc[x] = scnt; 53 if(x == u) break; 54 } 55 } 56 } 57 58 void find_scc(){ 59 scnt = dfs_clock = 0; 60 memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); 61 memset(sc,0,sizeof(sc)); 62 63 for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i); 64 } 65 66 int main(){ 67 while(scanf("%d %d",&n,&m) != EOF){ 68 init(); 69 for(int i = 0;i < m;i++){ 70 int u,v,w; 71 scanf("%d %d %d",&u,&v,&w);u++;v++; 72 addedges(u,v,w); 73 } 74 find_scc(); 75 for(int u = 1;u <= n;u++){ 76 for(int i = first[u];~i;i = e[i].next){ 77 int v = e[i].v; 78 if(sc[u] != sc[v]) d[sc[v]] = min(d[sc[v]],e[i].w); 79 } 80 } 81 82 LL ans = 0; 83 for(int i = 1;i <= scnt;i++) { 84 if(d[i] != INF) ans += d[i]; 85 } 86 printf("%I64d ",ans); 87 } 88 return 0; 89 }
poj 3114
缩点之后,存边的时候可以贪心,维持两个连通分量间的最小距离,
再用dijkstra,
最开始看到n是500,兴高采烈地用floyd---t掉了----
too--young--
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 #include<stack> 7 using namespace std; 8 9 const int maxn = 505; 10 const int INF = 1000000005; 11 int n,m,q; 12 int first[maxn],first1[maxn]; 13 int low[maxn],pre[maxn],sc[maxn]; 14 int ecnt,ecnt1,dfs_clock,scnt; 15 stack<int> S; 16 17 int d[maxn][maxn]; 18 int vis[maxn]; 19 int dis[maxn]; 20 21 struct Edge{ 22 int v,next,w; 23 }; 24 25 Edge e[maxn*maxn],e1[maxn*maxn]; 26 27 void init(){ 28 ecnt = ecnt1 = 0; 29 memset(first,-1,sizeof(first)); 30 } 31 32 void dijkstra(int s,int N){ 33 for(int i=1;i<=N;i++) dis[i]=INF,vis[i] = 0; 34 dis[s]=0; 35 36 for(int k=1;k<=N;k++){ 37 int p,m=INF; 38 for(int i=1;i<=N;i++) if(!vis[i]&&dis[i]<m) m=dis[p=i]; 39 vis[p]=1; 40 for(int i=1;i<=N;i++) dis[i]=min(dis[i],dis[p]+d[p][i]); 41 } 42 } 43 44 void addedges(int u,int v,int w){ 45 e[ecnt].v = v; 46 e[ecnt].w = w; 47 e[ecnt].next = first[u]; 48 first[u] = ecnt++; 49 } 50 51 void tarjan(int u,int fa){ 52 low[u] = pre[u] = ++dfs_clock; 53 S.push(u); 54 for(int i = first[u];~i;i = e[i].next){ 55 int v = e[i].v; 56 if(!pre[v]){ 57 tarjan(v,u); 58 low[u] = min(low[u],low[v]); 59 } 60 else if(!sc[v]) low[u] = min(low[u],pre[v]); 61 } 62 if(low[u] == pre[u]){ 63 scnt++; 64 for(;;){ 65 int x = S.top();S.pop(); 66 sc[x] = scnt; 67 if(x == u) break; 68 } 69 } 70 } 71 72 void find_scc(){ 73 scnt = dfs_clock = 0; 74 memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); 75 memset(sc,0,sizeof(sc)); 76 while(!S.empty()) S.pop(); 77 78 for(int i = 1;i <= n;i++) if(!pre[i]) tarjan(i,-1); 79 } 80 81 82 int main(){ 83 int kase = 0; 84 while(scanf("%d %d",&n,&m) != EOF && n){ 85 if(kase) puts("");kase++; 86 init(); 87 for(int i = 1;i <= m;i++){ 88 int u,v,w; 89 scanf("%d %d %d",&u,&v,&w); 90 addedges(u,v,w); 91 } 92 93 94 find_scc(); 95 //扫一遍边,边的两端在同一个连通分量的,权值设为0; 96 97 for(int i =1 ;i <= scnt;i++){ 98 for(int j = 1;j <= scnt;j++){ 99 if(i != j) d[i][j] = INF; 100 else d[i][j] = 0; 101 } 102 } 103 104 for(int u = 1;u <= n;u++){ 105 for(int i = first[u];~i;i = e[i].next){ 106 int v = e[i].v; 107 if(sc[u] != sc[v]) d[sc[u]][sc[v]] = min(d[sc[u]][sc[v]],e[i].w); 108 else d[sc[u]][sc[v]] = 0; 109 } 110 } 111 112 scanf("%d",&q); 113 while(q--){ 114 int u,v; 115 scanf("%d %d",&u,&v); 116 if(sc[u] == sc[v]) puts("0"); 117 else{ 118 dijkstra(sc[u],scnt); 119 if(dis[sc[v]] == INF) printf("Nao e possivel entregar a carta "); 120 else printf("%d ",dis[sc[v]]); 121 } 122 } 123 } 124 return 0; 125 }
poj 2253
如果一个点能够到达的其他的点也能够到达它,则把它叫做一个底,求图里面的所有的底
缩点,统计出度为0的块,块里面的所有的点都满足
话说数组开成5005为什么会t啊----开大点就过了----
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 using namespace std; 7 8 const int maxn = 20005; 9 int n,m; 10 int first[maxn]; 11 int low[maxn],pre[maxn],sc[maxn]; 12 int dout[maxn]; 13 int scnt,ecnt,dfs_clock; 14 int c[maxn]; 15 stack<int> S; 16 17 struct Edge{ 18 int v,next; 19 }e[10*maxn]; 20 21 void init(){ 22 ecnt = 0; 23 memset(first,-1,sizeof(first)); 24 memset(dout,0,sizeof(dout)); 25 } 26 27 void addedges(int u,int v){ 28 e[ecnt].v = v; 29 e[ecnt].next = first[u]; 30 first[u] = ecnt++; 31 } 32 33 void tarjan(int u,int fa){ 34 low[u] = pre[u] = ++dfs_clock; 35 S.push(u); 36 for(int i = first[u];~i;i = e[i].next){ 37 int v = e[i].v; 38 if(!pre[v]){ 39 tarjan(v,u); 40 low[u] = min(low[u],low[v]); 41 } 42 else if(!sc[v]) low[u] = min(low[u],pre[v]); 43 } 44 if(pre[u] == low[u]){ 45 scnt++; 46 for(;;){ 47 int x = S.top();S.pop(); 48 sc[x] = scnt; 49 if(x == u) break; 50 } 51 } 52 } 53 54 void find_scc(){ 55 while(!S.empty()) S.pop(); 56 dfs_clock = ecnt = 0; 57 memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); 58 memset(sc,0,sizeof(sc)); 59 for(int i = 1;i <= n;i++) if(!pre[i]) tarjan(i,-1); 60 } 61 62 int main(){ 63 while(scanf("%d",&n) != EOF && n){ 64 scanf("%d",&m); 65 init(); 66 for(int i = 1;i <= m;i++){ 67 int u,v; 68 scanf("%d %d",&u,&v); addedges(u,v); 69 } 70 find_scc(); 71 for(int u = 1;u <= n;u++){ 72 for(int i = first[u];~i;i = e[i].next){ 73 int v = e[i].v; 74 if(sc[u] != sc[v]) dout[sc[u]]++; 75 } 76 } 77 int num = 0; 78 for(int i = 1;i <= n;i++){ 79 if(dout[sc[i]] == 0) printf("%d ",i); 80 } 81 printf(" "); 82 } 83 return 0; 84 }
poj 2186
求出这样的点的个数,即其他点都能够到达它的点
先缩点,缩完点之后是一个DAG,DAG的终点(出度为0的点)就是要求的,
如果终点有多个,则不满足了,因为缩点之后不存在环,所以终点之间的点不能到达
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 using namespace std; 7 8 const int maxn = 20005; 9 int first[maxn]; 10 int low[maxn],pre[maxn],sc[maxn]; 11 int din[maxn],dout[maxn]; 12 int n,m; 13 int ecnt,scnt,dfs_clock; 14 stack<int> S; 15 16 struct Edge{ 17 int v,next; 18 }e[3*maxn]; 19 20 void init(){ 21 ecnt = 0; 22 memset(first,-1,sizeof(first)); 23 memset(din,0,sizeof(din)); 24 memset(dout,0,sizeof(dout)); 25 } 26 27 void addedges(int u,int v){ 28 e[ecnt].v = v; 29 e[ecnt].next = first[u]; 30 first[u] = ecnt++; 31 } 32 33 void dfs(int u){ 34 low[u] = pre[u] = ++dfs_clock; 35 S.push(u); 36 for(int i = first[u];~i;i = e[i].next){ 37 int v = e[i].v; 38 if(!pre[v]){ 39 dfs(v); 40 low[u] = min(low[u],low[v]); 41 } 42 else if(!sc[v]) low[u] = min(low[u],pre[v]); 43 } 44 if(pre[u] == low[u]){ 45 scnt++; 46 for(;;){ 47 int x = S.top();S.pop(); 48 sc[x] = scnt; 49 if(x == u) break; 50 } 51 } 52 } 53 54 void find_scc(){ 55 while(!S.empty()) S.pop(); 56 memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); 57 memset(sc,0,sizeof(sc)); 58 dfs_clock = scnt = 0; 59 for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i); 60 } 61 62 int main(){ 63 while( scanf("%d %d",&n,&m) != EOF){ 64 init(); 65 for(int i = 1;i <= m;i++){ 66 int u,v; 67 scanf("%d %d",&u,&v); 68 addedges(u,v); 69 } 70 find_scc(); 71 for(int u = 1;u <= n;u++){ 72 for(int i = first[u];~i;i = e[i].next){ 73 int v = e[i].v; 74 if(sc[u] != sc[v]){ 75 dout[sc[u]]++; 76 } 77 } 78 } 79 int c = 0; 80 for(int i = 1;i <= scnt;i++){ 81 if(dout[i] == 0) c++; 82 } 83 if(c > 1) printf("0 "); 84 else{ 85 int res = 0; 86 for(int i = 1;i <= n;i++){ 87 if(dout[sc[i]] == 0) res++; 88 } 89 printf("%d ",res); 90 } 91 } 92 return 0; 93 }