zoukankan      html  css  js  c++  java
  • BZOJ 2199: [Usaco2011 Jan]奶牛议会

    2199: [Usaco2011 Jan]奶牛议会

    Time Limit: 10 Sec  Memory Limit: 259 MB
    Submit: 375  Solved: 241
    [Submit][Status][Discuss]

    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"。

    Sample Input

    3 4
    1 Y 2 N
    1 N 2 N
    1 Y 3 Y
    1 Y 2 Y

    Sample Output

    YN?

    HINT

    Source

    Gold

    分析:

    2-SAT问题...

    考虑对于$xy$两个议案,如果$x$对应$Y$,$y$对应$N$,那么就代表这两个点至少选一个,也就是说$x$的$N$和$y$的$Y$不能同时选择,那么就代表存在两条边$<x(N),y(N)>,<y(Y),x(Y)>$...然后如果$dfs$发现存在一个议案选$Y$必须选$N$,选$N$必须选$Y$,那么就不存在合法方案,否则如果存在选$Y$必须$N$,那么就只选$N$就好了...

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    //by NeighThorn
    using namespace std;
    
    const int maxn=2000+5,maxm=8000+5;
    
    int n,m,cnt,hd[maxn],to[maxm],nxt[maxm],vis[maxn],cho[maxn],can[maxn];
    
    char s[2][3];
    
    inline int check(char a){
    	return a=='Y';
    }
    
    inline void add(int x,int y){
    	to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
    }
    
    inline bool dfs(int x){
    	if(cho[x^1]) return false;
    	vis[x]=cho[x]=1;
    	for(int i=hd[x];i!=-1;i=nxt[i])
    		if(!vis[to[i]])
    			if(!dfs(to[i]))
    				return false;
    	return true;
    }
    
    signed main(void){
    	scanf("%d%d",&n,&m);
    	memset(hd,-1,sizeof(hd));
    	for(int i=1,x,y,x1,y1,x2,y2;i<=m;i++){
    		scanf("%d%s%d%s",&x,s[0],&y,s[1]);
    		x1=x<<1|check(s[0][0]),y1=y<<1|(check(s[1][0])^1);
    		y2=y<<1|check(s[1][0]),x2=x<<1|(check(s[0][0])^1);
    		add(x1,y1);add(y2,x2);
    	}
    	for(int i=1;i<=n;i++){
    		memset(cho,0,sizeof(cho));
    		memset(vis,0,sizeof(vis));
    		can[i<<1  ]=dfs(i<<1  );
    		memset(cho,0,sizeof(cho));
    		memset(vis,0,sizeof(vis));
    		can[i<<1|1]=dfs(i<<1|1);
    	}
    	for(int i=1;i<=n;i++)
    		if(!can[i<<1]&&!can[i<<1|1])
    			return puts("IMPOSSIBLE"),0;
    	for(int i=1;i<=n;i++){
    		if(!can[i<<1]) cho[i<<1]=-1,cho[i<<1|1]=1;
    		else if(!can[i<<1|1]) cho[i<<1|1]=-1,cho[i<<1]=1;
    		else cho[i<<1]=1,cho[i<<1|1]=1;
    	}
    	for(int i=1;i<=n;i++){
    		if(cho[i<<1]==-1) printf("N");
    		else if(cho[i<<1|1]==-1) printf("Y");
    		else printf("?");
    	}
    	return 0;
    }
    

      


    By NeighThorn

  • 相关阅读:
    基本MVVM 和 ICommand用法举例(转)
    WPF C# 命令的运行机制
    628. Maximum Product of Three Numbers
    605. Can Place Flowers
    581. Shortest Unsorted Continuous Subarray
    152. Maximum Product Subarray
    216. Combination Sum III
    448. Find All Numbers Disappeared in an Array
    268. Missing Number
    414. Third Maximum Number
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6603604.html
Copyright © 2011-2022 走看看