zoukankan      html  css  js  c++  java
  • [POJ 1417]true liars

    题目传送-POJ1417

    题意:

    一共有(p1)个好人,(p2)个坏人.
    现在有(m)句话(a,b,YES/NO)
    表示(a)(b)是否是好人
    好人都说真话,坏人都说假话
    问方案是否唯一,并输出唯一的方案
    (p1,p2le300,mle1000)

    题解:

    观察性质发现:当为NO时,ab好坏相反,否则相同
    那么考虑并查集维护出敌对和友好关系
    其中每一个团有一个敌对团,即两个团之间的好坏必然相反
    那么把这些敌对的数量搞出来,背包一发就行了
    路径输出不解释了

    过程:

    并查集记得把关系都建满了..

    代码:

    const int N=1210;
    int p1,p2,n,m;
    int fat[N<<1],sz[N<<1];
    char s[20];
    int father(int x) {return fat[x]==x ? x : fat[x]=father(fat[x]);}
    inline void Union(int x,int y) {
    	int fx=father(x),fy=father(y);
    	if(fx!=fy) {fat[fx]=fy; sz[fy]+=sz[fx]; sz[fx]=0;}
    }
    int used[N];
    pii a[N][2]; int tot=0;
    int f[N][N],fr[N][N];
    int cho[N],ind=0;
    void Print(int dep,int j) {
    	if(dep==0) return;
    	int type=fr[dep][j];
    	cho[++ind]=a[dep][type].S;
    	Print(dep-1,j-a[dep][type].F);
    }
    int ans[N],res=0;
    signed main() {
    	while(scanf("%d %d %d",&m,&p1,&p2) && (m || p1 || p2)) {
    		ind=tot=res=0; mem(used,0); bool fl=1;
    		n=p1+p2; mem(sz,0); mem(f,0);
    		for(int i=1;i<=n*2;i++) fat[i]=i;
    		for(int i=1;i<=n;i++) sz[i]=1;
    		for(int i=1;i<=m;i++) {
    			int x,y; read(x); read(y); scanf("%s",s+1);
    			Union(x+(s[1]=='y' ? 0 : n),y);
    			Union(x,y+(s[1]=='y' ? 0 : n));
    			if(s[1]=='y') Union(x+n,y+n);
    		}
    		for(int i=n+1;i<=2*n;i++) {
    			int fx=father(i),fy=father(i-n);
    			// printf("%d %d
    ",fx,fy);
    			if(fx==fy) {puts("no"); fl=0; break;}
    			if(used[fx]) {assert(used[fy]); continue;}
    			used[fx]=used[fy]=1;
    			a[++tot][0]=mp(sz[fx],fx);
    			a[tot][1]=mp(sz[fy],fy);
    		}
    		if(!fl) continue;
    		f[0][0]=1;
    		// printf("tot=%d
    ",tot);
    		// for(int i=1;i<=tot;i++) printf("%d %d
    ",a[i][0].F,a[i][1].F);
    		for(int i=1;i<=tot;i++) {
    			int bd=a[i][0].F;
    			for(int j=p1;j>=bd;j--)
    				if(f[i-1][j-bd]) {
    					fr[i][j]=0;
    					f[i][j]+=f[i-1][j-bd];
    					if(f[i][j]>1) f[i][j]=2;
    				}
    			bd=a[i][1].F;
    			for(int j=p1;j>=bd;j--)
    				if(f[i-1][j-bd]) {
    					fr[i][j]=1;
    					f[i][j]+=f[i-1][j-bd];
    					if(f[i][j]>1) f[i][j]=2;
    				}
    		}
    		if(f[tot][p1]==1) {
    			Print(tot,p1);
    			for(int i=1;i<=n;i++) {
    				int anc=father(i);
    				for(int j=1;j<=ind;j++)
    					if(anc==cho[j]) {ans[++res]=i; break;}
    			}
    			sort(ans+1,ans+res+1);
    			for(int i=1;i<=res;i++)
    				printf("%d
    ",ans[i]);
    			puts("end");
    		} else puts("no");
    	}
    	return 0;
    }
    

    用时:1h

  • 相关阅读:
    蓝桥杯_基础_杨辉三角
    蓝桥杯_基础_数组特征
    蓝桥杯_基础_美丽的图形
    脉象
    词根汇总
    蓝桥杯 入门训练 Fibonacci数列 解析
    制作tomcat重启.bat文件
    day23(023-递归练习)
    day27(027-反射&JDK新特性)
    day25(025-多线程(下)&GUI)
  • 原文地址:https://www.cnblogs.com/functionendless/p/9498182.html
Copyright © 2011-2022 走看看