题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=27010
思路:首先Tarjan标记桥,然后对于dfs遍历整个图,我们可以得出一个简单的结论,就是如果一个双连通分量中存在奇圈,那么这个双连通分量中的所有点都可行,于是我们可以dfs染色判奇圈。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define MAXN 22222 7 8 struct Edge{ 9 int v,next; 10 }edge[MAXN<<1]; 11 12 int n,m,NE; 13 int head[MAXN]; 14 15 void Insert(int u,int v) 16 { 17 edge[NE].v=v; 18 edge[NE].next=head[u]; 19 head[u]=NE++; 20 } 21 22 int low[MAXN],dfn[MAXN],cnt; 23 bool bridge[MAXN<<1]; 24 bool mark[MAXN]; 25 26 void Tarjan(int u,int father) 27 { 28 low[u]=dfn[u]=++cnt; 29 mark[u]=true; 30 for(int i=head[u];i!=-1;i=edge[i].next){ 31 int v=edge[i].v; 32 if(v==father)continue; 33 if(dfn[v]==0){ 34 Tarjan(v,u); 35 low[u]=min(low[u],low[v]); 36 if(low[v]>dfn[u]){ 37 bridge[i]=bridge[i^1]=true; 38 } 39 }else if(mark[v]){ 40 low[u]=min(low[u],dfn[v]); 41 } 42 } 43 } 44 45 int flag,ans; 46 int color[MAXN]; 47 48 void dfs(int u,int state) 49 { 50 cnt++; 51 color[u]=state; 52 for(int i=head[u];i!=-1;i=edge[i].next){ 53 int v=edge[i].v; 54 if(bridge[i])continue; 55 if(color[v]&&color[u]==color[v]){ 56 flag=1; 57 }else if(color[v]==0){ 58 dfs(v,3-state); 59 } 60 } 61 } 62 63 int main() 64 { 65 int _case,u,v,t=1; 66 scanf("%d",&_case); 67 while(_case--){ 68 scanf("%d%d",&n,&m); 69 NE=0; 70 memset(head,-1,sizeof(head)); 71 while(m--){ 72 scanf("%d%d",&u,&v); 73 Insert(u,v); 74 Insert(v,u); 75 } 76 cnt=0; 77 memset(mark,false,sizeof(mark)); 78 memset(dfn,0,sizeof(dfn)); 79 memset(bridge,false,sizeof(bridge)); 80 for(int i=0;i<n;i++)if(dfn[i]==0)Tarjan(i,i); 81 memset(color,0,sizeof(color)); 82 ans=0; 83 for(int i=0;i<n;i++){ 84 if(color[i]==0){ 85 flag=0; 86 cnt=0; 87 dfs(i,1); 88 if(flag)ans+=cnt; 89 } 90 } 91 printf("Case %d: %d\n",t++,ans); 92 } 93 return 0; 94 } 95 96 97 98