您的位置:首页 > 其它

bzoj 2199: [Usaco2011 Jan]奶牛议会

2017-12-23 11:14 483 查看

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 3000005
using 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=(x
c7c0
3+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;
}

        
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: