题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26961
思路:u表示留下,~u表示离开,同理v,对于+u,-v,我们可以这样来定义:若u离开,则v必须留下,如v离开,则u必须留下,于是我们可以连边u+n->v,v+n->u,后面的同理。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stack> 6 #include<vector> 7 #include<queue> 8 using namespace std; 9 #define MAXN 20000 10 #define MAXM 444444 11 12 struct Edge{ 13 int v,next; 14 }edge[MAXM]; 15 16 int n,m,NE; 17 int head[MAXN]; 18 19 void Insert(int u,int v) 20 { 21 edge[NE].v=v; 22 edge[NE].next=head[u]; 23 head[u]=NE++; 24 } 25 26 int cnt,bcc_count; 27 int low[MAXN],dfn[MAXN],color[MAXN]; 28 bool mark[MAXN]; 29 stack<int>S; 30 31 void Tarjan(int u) 32 { 33 low[u]=dfn[u]=++cnt; 34 mark[u]=true; 35 S.push(u); 36 for(int i=head[u];i!=-1;i=edge[i].next){ 37 int v=edge[i].v; 38 if(dfn[v]==0){ 39 Tarjan(v); 40 low[u]=min(low[u],low[v]); 41 }else if(mark[v]){ 42 low[u]=min(low[u],dfn[v]); 43 } 44 } 45 if(low[u]==dfn[u]){ 46 int v; 47 bcc_count++; 48 do{ 49 v=S.top(); 50 S.pop(); 51 mark[v]=false; 52 color[v]=bcc_count; 53 }while(u!=v); 54 } 55 } 56 57 int opp[MAXN]; 58 bool Judge() 59 { 60 for(int i=1;i<=n;i++){ 61 if(color[i]==color[i+n])return false; 62 //opp[x]保存的是和编号为x的连通分量矛盾的连通分量的编号 63 opp[color[i]]=color[i+n]; 64 opp[color[i+n]]=color[i]; 65 } 66 return true; 67 } 68 69 vector<vector<int> >g; 70 vector<int>ans; 71 int degree[MAXN]; 72 int vis[MAXN]; 73 74 void TopSort() 75 { 76 queue<int>que; 77 for(int i=1;i<=bcc_count;i++){ 78 if(degree[i]==0)que.push(i); 79 } 80 while(!que.empty()){ 81 int u=que.front(); 82 que.pop(); 83 if(vis[u]==0){ 84 //染色 85 vis[u]=1; 86 vis[opp[u]]=-1; 87 } 88 for(int i=0;i<g[u].size();i++){ 89 degree[g[u][i]]--; 90 if(degree[g[u][i]]==0)que.push(g[u][i]); 91 } 92 } 93 } 94 95 96 int main() 97 { 98 int _case,t=1,a,b,u,v; 99 scanf("%d",&_case); 100 while(_case--){ 101 scanf("%d %d",&m,&n); 102 NE=0; 103 memset(head,-1,sizeof(head)); 104 while(m--){ 105 scanf("%d%d",&a,&b); 106 u=abs(a),v=abs(b); 107 if(a>0&&b>0)Insert(u+n,v),Insert(v+n,u); 108 else if(a>0&&b<0)Insert(u+n,v+n),Insert(v,u); 109 else if(a<0&&b>0)Insert(u,v),Insert(v+n,u+n); 110 else Insert(u,v+n),Insert(v,u+n); 111 } 112 cnt=bcc_count=0; 113 memset(mark,false,sizeof(mark)); 114 memset(dfn,0,sizeof(dfn)); 115 memset(color,0,sizeof(color)); 116 for(int i=1;i<=2*n;i++)if(dfn[i]==0)Tarjan(i); 117 printf("Case %d: ",t++); 118 if(!Judge()){ 119 puts("No"); 120 continue; 121 } 122 puts("Yes"); 123 //反向建图 124 memset(degree,0,sizeof(degree)); 125 g.clear(); 126 g.resize(2*n+2); 127 for(int u=1;u<=2*n;u++){ 128 for(int i=head[u];i!=-1;i=edge[i].next){ 129 int v=edge[i].v; 130 if(color[u]!=color[v]){ 131 g[color[v]].push_back(color[u]); 132 degree[color[u]]++; 133 } 134 } 135 } 136 memset(vis,0,sizeof(vis)); 137 TopSort(); 138 ans.clear(); 139 for(int i=1;i<=n;i++){ 140 if(vis[color[i]]==1)ans.push_back(i); 141 } 142 printf("%d",(int)ans.size()); 143 sort(ans.begin(),ans.end()); 144 for(int i=0;i<(int)ans.size();i++){ 145 printf(" %d",ans[i]); 146 } 147 puts(""); 148 } 149 return 0; 150 }