http://codeforces.com/gym/101246/problem/G
题意:
给出一个有向图,现在可以把图中的任意一条边改为无向边,问强连通分量最多可以有多少个点,在此情况下输出所有能改的边。
思路:
先dfs求出每个点能到达的点,用一个二维数组来存一下。
接下来枚举每一条边,把 u-v 这条边改为无向边,那么如果存在一点k,满足u->k并且k->v或者v->k并且k->u,那么k肯定是在这个强连通分量当中的。这样就可以计算出修改每一条边时所对应的点的个数。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<sstream> 6 #include<vector> 7 #include<stack> 8 #include<queue> 9 #include<cmath> 10 #include<map> 11 #include<cstdio> 12 #include<set> 13 using namespace std; 14 typedef long long ll; 15 typedef pair<int,int> pll; 16 const int INF = 0x3f3f3f3f; 17 const int maxn=1000+5; 18 19 int n, m; 20 21 struct Edge 22 { 23 int u, v; 24 }edge[20000+5]; 25 26 int vis[maxn]; 27 int mp[maxn][maxn]; 28 29 vector<int> G[maxn]; 30 31 void dfs(int u, int src) 32 { 33 for(int i=0;i<G[u].size();i++) 34 { 35 int v=G[u][i]; 36 if(vis[v]) continue; 37 vis[v]=1; 38 mp[src][v]=1; 39 dfs(v,src); 40 } 41 } 42 43 int main() 44 { 45 freopen("input.txt","r",stdin); 46 freopen("output.txt","w",stdout); 47 //freopen("in.txt","r",stdin); 48 while(~scanf("%d%d", &n, &m)) 49 { 50 for(int i=1;i<=n;i++) G[i].clear(); 51 for(int i=1;i<=m;i++) 52 { 53 scanf("%d%d",&edge[i].u, &edge[i].v); 54 G[edge[i].u].push_back(edge[i].v); 55 } 56 57 if(m==0) {puts("1");puts("0");continue;} 58 memset(mp,0,sizeof(mp)); 59 for(int i=1;i<=n;i++) 60 { 61 mp[i][i]=1; 62 memset(vis,0,sizeof(vis)); 63 vis[i]=1; 64 dfs(i,i); 65 } 66 67 int now, MAX=0, cnt=0; 68 int ans[20000+5]; 69 for(int i=1;i<=m;i++) 70 { 71 now=0; 72 int u=edge[i].u, v=edge[i].v; 73 for(int j=1;j<=n;j++) 74 if(mp[u][j] && mp[j][v] || mp[v][j] && mp[j][u]) now++; 75 76 if(now>MAX) {MAX=now;cnt=0;ans[cnt++]=i;} 77 else if(now==MAX) ans[cnt++]=i; 78 } 79 80 printf("%d %d ",MAX,cnt); 81 for(int i=0;i<cnt;i++) 82 { 83 printf("%d%c",ans[i],i==cnt-1?' ':' '); 84 } 85 } 86 return 0; 87 }