bzoj 2199: [Usaco2011 Jan]奶牛议会

来源:互联网 发布:msp430用什么软件 编辑:程序博客网 时间:2024/05/16 14:13

Description

由于对Farmer John的领导感到极其不悦,奶牛们退出了农场,组建了奶牛议会。议会以“每头牛 都可以获得自己想要的”为原则,建立了下面的投票系统: M只到场的奶牛 (1 <= M <= 4000) 会给N个议案投票(1 <= N <= 1,000) 。每只 奶牛会对恰好两个议案 B_i and C_i (1 <= B_i <= N; 1 <= C_i <= N)投 出“是”或“否”(输入文件中的'Y'和'N')。他们的投票结果分别为VB_i (VB_i in {'Y', 'N'}) and VC_i (VC_i in {'Y', 'N'})。 最后,议案会以如下的方式决定:每只奶牛投出的两票中至少有一票和最终结果相符合。 例如Bessie给议案1投了赞成'Y',给议案2投了反对'N',那么在任何合法的议案通过 方案中,必须满足议案1必须是'Y'或者议案2必须是'N'(或者同时满足)。 给出每只奶牛的投票,你的工作是确定哪些议案可以通过,哪些不能。如果不存在这样一个方案, 输出"IMPOSSIBLE"。如果至少有一个解,输出: Y 如果在每个解中,这个议案都必须通过 N 如果在每个解中,这个议案都必须驳回 ? 如果有的解这个议案可以通过,有的解中这个议案会被驳回 考虑如下的投票集合: - - - - - 议案 - - - - - 1 2 3 奶牛 1 YES NO 奶牛 2 NO NO 奶牛 3 YES YES 奶牛 4 YES YES 下面是两个可能的解: * 议案 1 通过(满足奶牛1,3,4) * 议案 2 驳回(满足奶牛2) * 议案 3 可以通过也可以驳回(这就是有两个解的原因) 事实上,上面的问题也只有两个解。所以,输出的答案如下: YN?

Input

* 第1行:两个空格隔开的整数:N和M * 第2到M+1行:第i+1行描述第i只奶牛的投票方案:B_i, VB_i, C_i, VC_i

Output

* 第1行:一个含有N个字符的串,第i个字符要么是'Y'(第i个议案必须通过),或者是'N' (第i个议案必须驳回),或者是'?'。 如果无解,输出"IMPOSSIBLE"。
       上了黑板手推就是思路比较清晰呀。

       关系很一样,也就是“或”的关系,不过问法比较有意思,问的是第i个议案是必须被通过,必须不被通过,可被也可不被,还是不属于任何方案。

       翻译一下题意就是,如果某个可行解包含Y,却没有可行解包含N,就输出Y,以此类推。

       不知道有没有可行解能包含它,我们就拿它构造可行解啊,如果能构造出来可行解就可行,构造不出来就不行,由于连的边是依赖关系,所以我们可以一直走,走到没有依赖关系为止,看有没有一个点的正反被这个可行解同时包含即可。

       下附AC代码。

#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<stack>#define maxn 3000005using namespace std;//0:选,1:不选,2:存在,3:不存在 int n,m,k,tot,num,cnt;int head[maxn<<2],to[6*maxn],nex[6*maxn],pre[6*maxn];void add(int x,int y){to[++tot]=y;nex[tot]=head[x];head[x]=tot;}int low[maxn<<2],dfn[maxn<<2],bel[maxn<<2];bool vis[maxn<<2];stack<int>s;void tarjan(int now){low[now]=dfn[now]=++cnt;vis[now]=1;s.push(now);for(int i=head[now];i;i=nex[i]){if(!dfn[to[i]]){tarjan(to[i]);low[now]=min(low[now],low[to[i]]);}else if(vis[to[i]]){low[now]=min(low[now],dfn[to[i]]);}}if(low[now]==dfn[now]){num++;int temp;do{temp=s.top();s.pop();bel[temp]=num;vis[temp]=0;}while(temp!=now);}return;}int main(){memset(pre,-1,sizeof(pre));scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);x--;y--;int x1=((x<<2)|1),y1=((y<<2)|1);x<<=2;y<<=2;add(x1,y);add(y1,x);}for(int i=1;i<=k;i++){int x,last;scanf("%d%d",&x,&last);last--;for(int j=1;j<x;j++){int y;scanf("%d",&y);y--;pre[y]=last;last=y;}}for(int i=0;i<n;i++){int x1=(i<<2),x2=(x1|1),x3=(x2+1),x4=(x3+1);add(x1,x3);add(x4,x2);if(pre[i]!=-1){int j=pre[i];int y1=(j<<2),y2=(y1|1),y3=(y2+1),y4=(y3+1);add(y3,x3);add(x4,y4);add(y3,x2);add(x1,y4);}} for (int i=0;i<(n<<2);i++)    if (!dfn[i]) tarjan(i);    for (int i=0;i<(n<<2);i++)    if (bel[i]==bel[i^1]) {printf("NIE");return 0;}printf("TAK\n");return 0;}