CodeForces 506B/505D Mr. Kitayuta's Technology

Portal:http://codeforces.com/problemset/problem/506/B

    http://codeforces.com/problemset/problem/505/D 

好题

给n个城市,m条有向边,求出最少的有向边使得其构成的图与原图等势

对于每个连通分量:

如果无环,那么只需要需要n-1条边完成联通

如果有环,则只需要n条边完成联通

所以这题只要判下连通分量,再看有几个连通分量有环即可

解法一:无向图遍历求强连通分量再把强连通分量所代表的联通分量dfs判环,如下

Memory: 10440 KB   Time: 498 MS
 1 #include<iostream>
 2 #include<algorithm>
 3 #include<set>
 4 #include<cstdio>
 5 #include<cstdlib>
 6 #include<cmath>
 7 #include<vector>
 8 using namespace std;
 9 #define FOR(i,j,k) for(int i=j;i<=k;i++)
10 #define FORD(i,j,k) for(int i=j;i>=k;i--)
11 #define LL long long
12 #define SZ(x) int(x.size())
13 #define maxn 100010
14 int n,m,x,y;
15 bool  circle=true;
16 int vis[maxn],vis2[maxn];
17 vector<int> neg[maxn],adj[maxn];
18 vector<int> dot;
19 void ndfs(int start)
20 {
21     dot.push_back(start);
22     vis[start]=1;
23     FOR(i,0,SZ(neg[start])-1)
24     {
25         if(!vis[neg[start][i]]) ndfs(neg[start][i]);
26         
27     }
28     return;
29 }
30 void adfs(int start)
31 {
32     vis2[start]=1;
33     FOR(i,0,SZ(adj[start])-1)
34     {
35         if(!vis2[adj[start][i]]) adfs(adj[start][i]); 
36         else if(vis2[adj[start][i]]==1)circle=false; 
37     }
38     vis2[start]=2;
39     return;
40 }
41 int main()
42 {
43 cin>>n>>m;
44 FOR(i,1,m)
45 {
46     cin>>x>>y;
47     neg[x].push_back(y);
48     neg[y].push_back(x);
49     adj[x].push_back(y);
50 }
51 int ans=n;
52 FOR(i,1,n)
53 {
54     circle=1;
55     if(!vis[i]) 
56     {
57     dot.clear(); 
58     ndfs(i);  
59     FOR(i,0,SZ(dot)-1)
60     if (!vis2[dot[i]]) adfs(dot[i]);
61     ans-=circle;
62     }
63 }
64 cout<<ans<<endl;
65 return 0;
66 }
我在想函数名字到底取afs好还是adfs好

解法二:在无向图中维护并查集求强连通分量再把强连通分量所代表的联通分量用拓扑排序判环,如下

Memory: 7820 KB   Time: 514 MS
 1 #include<iostream>
 2 #include<algorithm>
 3 #include<set>
 4 #include<cstdio>
 5 #include<cstdlib>
 6 #include<cmath>
 7 #include<vector>
 8 using namespace std;
 9 #define FOR(i,j,k) for(int i=j;i<=k;i++)
10 #define FORD(i,j,k) for(int i=j;i>=k;i--)
11 #define LL long long
12 #define SZ(x) int(x.size())
13 #define maxn 100010
14 vector<int> G[maxn];
15 int n,m,x,y,T;
16 int father[maxn],val[maxn],circle[maxn],vis[maxn],clock[maxn];
17 int setfind(int x)
18 {
19     int fa=father[x];
20     if(fa==x) return x;
21     else return father[x]=setfind(fa);
22 }
23 void setunion(int x,int y)
24 {
25     int X=setfind(x);
26     int Y=setfind(y);
27     if(X==Y) return;
28     if(val[X]>val[Y]) father[Y]=X;
29     else father[X]=Y;
30     if(val[X]==val[Y]) val[X]++;
31     return;
32 }
33 void dfs(int start)
34 {
35     vis[start]=1;
36     FOR(i,0,SZ(G[start])-1)
37     if(!vis[G[start][i]]) dfs(G[start][i]);
38     clock[start]=++T;
39     return;
40 }
41 int main()
42 {
43 cin>>n>>m;
44 FOR(i,1,n)
45 {father[i]=i;val[i]=1;}
46 FOR(i,1,m)
47 {
48     cin>>x>>y;
49     G[x].push_back(y);
50     setunion(x,y);
51 }
52 FOR(i,1,n)
53 if(!vis[i]) dfs(i);
54 FOR(i,1,n)
55 FOR(j,0,SZ(G[i])-1)
56 if(clock[i]<clock[G[i][j]]) circle[setfind(i)]=1;
57 int ans=n;
58 FOR(i,1,n)
59 if(i==setfind(i))if(!circle[setfind(i)]) ans--;
60 cout<<ans<<endl;
61 return 0;
62 }
Mr. Kitayuta's Black Technology

其实求连通分量还可以用染色

  判有向环可以用并查集乱搞

反正就是怎么搞都能过

原文地址:https://www.cnblogs.com/mukoiaoi/p/5655796.html