Gold
题解:2-SAT+拓扑序+bitset
x表选Y,x'表示选N
对于每一个投票方案: x'->y ,y'->x
然后用tarjan缩点,判断是否存在可行解。
如果存在可行解,对于缩点后的图用拓扑序求出每个点有哪些点能到达他。
如果x->x',那么一定只能选N
如果x'->x,那么一定只能选Y
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<bitset>#include<queue>#define N 100003using namespace std;int n,m,tot,tt;int point[N],v[N],nxt[N],cnt,sz,top;int head[N],u[N],next[N];int st[N],belong[N],ins[N],low[N],dfsn[N],vis[N];bitset<2003> mp[2003],mp1[2003];void add(int x,int y){ tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;// cout<<x<<" "<<y<<endl;}void build(int x,int y){ tt++; next[tt]=head[x]; head[x]=tt; u[tt]=y; //cout<<x<<" "<<y<<endl;}void tarjan(int x){ st[++top]=x; ins[x]=1; low[x]=dfsn[x]=++sz; for (int i=point[x];i;i=nxt[i]) { int j=v[i]; if (!dfsn[j]) tarjan(j),low[x]=min(low[x],low[j]); else if (ins[j]) low[x]=min(low[x],dfsn[j]); } if (low[x]==dfsn[x]) { int j; ++cnt; do{ j=st[top--]; belong[j]=cnt; ins[j]=0; }while (j!=x); }}int main(){ freopen("a.in","r",stdin); freopen("my.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { int x,y,xx,yy; char s[10],s1[10]; scanf("%d%s%d%s",&x,&s,&y,&s1); if (s[0]=='Y') xx=x+n; else xx=x,x=x+n; if (s1[0]=='Y') yy=y+n; else yy=y,y=y+n; add(xx,y); add(yy,x); } for (int i=1;i<=2*n;i++) if (!dfsn[i]) tarjan(i); for (int i=1;i<=n;i++) if (belong[i]==belong[i+n]) { PRintf("IMPOSSIBLE/n"); return 0; } memset(ins,0,sizeof(ins)); for (int i=1;i<=2*n;i++) for (int j=point[i];j;j=nxt[j]) { int r1=belong[i]; int r2=belong[v[j]]; if (r1!=r2) { ins[r2]++; build(r1,r2); } } //for (int i=1;i<=2*n;i++) cout<<belong[i]<<" ";// cout<<endl; for (int i=1;i<=2*n;i++) mp[belong[i]][i]=1; for (int i=1;i<=cnt;i++) mp1[i]=mp[i]; queue<int> p; for (int i=1;i<=2*n;i++) if (!ins[i]) p.push(i); while (!p.empty()) { int now=p.front(); p.pop(); for (int i=head[now];i;i=next[i]){ mp[u[i]]|=mp[now]; ins[u[i]]--; if (!ins[u[i]]) p.push(u[i]); } } memset(vis,-1,sizeof(vis));/* for (int i=1;i<=cnt;i++) { for (int j=1;j<=2*n;j++) cout<<mp[i][j]; cout<<endl; }*/ for (int i=1;i<=cnt;i++) { for (int j=1;j<=n;j++){ if (mp1[i][j]&&mp[i][j+n]) vis[j]=1; else if (mp1[i][j+n]&&mp[i][j]) vis[j]=0; } } for (int i=1;i<=n;i++) if (vis[i]==1) printf("Y"); else if (vis[i]==0) printf("N"); else printf("?"); printf("/n");}
新闻热点
疑难解答