题意:n个人参与投票,被选的人有m个,每一个人都有两个选择:让某个人当选,让某个人下台。。问是否存在一个方式,能够每一个选民的至少一个选择。
思路:如果一个人的第一个选择没有被满足,则另一个选择一定要被满足、
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <queue> #include <stack> using namespace std; const int N = 20009; const int M = 8009; struct LT{ int nex,to; } L[N<<2]; int F[M<<1],cnt; void add(int f,int t) { L[cnt].nex = F[f]; L[cnt].to = t; F[f] = cnt++; } struct ET{ int nex,to; } EL[N<<2]; int EF[M<<1],Ecnt; void Eadd(int f,int t) { EL[Ecnt].nex = EF[f]; EL[Ecnt].to = t; EF[f] = Ecnt++; } int n,m; void init() { memset(F,0,sizeof(F)); memset(EF,0,sizeof(EF)); cnt = 1; Ecnt = 1; } int dfn[M<<1],col[M<<1],low[M<<1],post[M<<1],ind,color; stack<int> S; void tarjan(int k) { low[k] = dfn[k] = ind++; S.push(k),post[k] = 1; for(int i=F[k];i;i=L[i].nex) { int to = L[i].to; if(!dfn[to]) { tarjan(to); low[k] = min(low[to],low[k]); }else if(post[to]&&dfn[to]<low[k]) low[k] = dfn[to]; } if(low[k]==dfn[k]) { int i;color++; for(i=S.top(),S.pop();i!=k;i=S.top(),S.pop()) { post[i] = 0,col[i] = color; Eadd(color,i); } Eadd(color,i); post[i] = 0,col[i] = color; } } void solve() { ind = 1,color = 0; memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); for(int i=0;i<(m<<1);i++) if(!dfn[i]) tarjan(i); for(int i=0;i<m;i++) if(col[i]==col[i+m]) { printf("No\n"); return ; } printf("Yes\n"); int ans[M]; memset(ans,-1,sizeof(ans)); for(int i=1;i<=color;i++) if(ans[i]==-1) for(int j=EF[i];j;j=EL[j].nex) { ans[i] = 1; ans[col[(EL[j].to+m)%(m<<1)]] = 0; } int out[M],tmp=0; for(int i=0;i<m;i++) if(ans[col[i]]==1) { out[tmp++] = i+1; } printf("%d",tmp); for(int i=0;i<tmp;i++) printf(" %d",out[i]); printf("\n"); } int main() { freopen("in.txt","r",stdin); int cas,T =1; scanf("%d",&cas); while(cas--) { scanf("%d%d",&n,&m); int a,b,a1,b1; init(); for(int i=0;i<n;i++) { scanf("%d%d",&a,&b); if(a<0) a = m-a; if(b<0) b = m-b; a--;b--; a1 = (a+m) %(m<<1); b1 = (b+m) %(m<<1); add(a1,b); add(b1,a); } printf("Case %d: ",T++); solve(); } return 0; }