【F - True Liars】

思路:

  • 带权并查集(种类)
  • 注意 par[i]FIND(i) 的区别。
  • dp+输出路径
  • 注意cur卡了很久
  • 最奇怪的就是maxn的大小,605、1005都会WA1000、1111AC

代码:

  • 63ms 4696kB
//63ms		4696kB


#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>

using namespace std;

const int maxn = 1000;

int par[maxn];
int val[maxn];
int N,P,Q;
struct GROUP{
	int head;
	int a;
	int b;
};
GROUP group[maxn];int cnt;
int dp[maxn][maxn];
int ans[maxn];int cntt;

void INIT(){
	cnt = 0 ;
	cntt = 0;
	memset(group , 0 , sizeof(group));
	memset(dp , 0 , sizeof(dp));
	memset(val , 0 , sizeof(val));
	memset(par , -1 , sizeof(par));
	return ;
}

int FIND(int i){
	if(par[i] == -1)
		return i;
	int temp = par[i];
	par[i] = FIND(par[i]);
	val[i] = (val[i] + val[temp]) % 2;
	return par[i];
}

void UNION(int w,int l,int r,int parl,int parr){
	par[parr] = parl;
	val[parr] = (val[l] + w - val[r] + 2) % 2;
	return ;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	while(cin>>N>>P>>Q){
		INIT();
		int l , r;
		string str;
		if(!(P+N+Q))
			break; 
		while(N--){
			cin>>l>>r>>str;
			int w;
			if(str.size() == 3)
				w = 0;
			else
				w = 1;
			//YES代表同类,w=0
			//NO 代表异类,w=1
			int parl = FIND(l) ;
			int parr = FIND(r) ;
			if(parr == parl)
				;
			else
				UNION(w , l , r , parl , parr);
		}
		for(int i=1;i<=P+Q;i++)
			FIND(i);
		for(int i=1;i<=P+Q;i++)
			if(par[i] == -1)
				group[++cnt].head = i;
		for(int i=1;i<=P+Q;i++){
			int j;
			for(j=1;j<=cnt;j++)
				if(FIND(i) == group[j].head)
					//注意不是par[i] 
					break;
			if(val[i])
				group[j].b++;
			else
				group[j].a++;
		}
		dp[0][0] = 1;
		for(int i=1;i<=cnt;i++){
			for(int j=P;j>=0;j--){
				if(j>=group[i].a)
					dp[i][j] += dp[i-1][j-group[i].a];
				if(j>=group[i].b)
					dp[i][j] += dp[i-1][j-group[i].b];
			}
		}
		if(dp[cnt][P] != 1)
			printf("no\n");
		else{
			int cur = P;
			while(cnt){ 
				//一定是 1 和 0
				if(dp[cnt-1][cur-group[cnt].a]){
					cur -= group[cnt].a;
					for(int i=1;i<=P+Q;i++)
						if(FIND(i) == group[cnt].head && !val[i])
						//注意不是par[i],那样会漏掉集合主元 
							ans[cntt++] = i;
				}
				else{
					cur -= group[cnt].b;
					for(int i=1;i<=P+Q;i++)
						if(FIND(i) == group[cnt].head && val[i])
							ans[cntt++] = i; 
				}
				//追溯路径时只能是一种或零种可能
				cnt--;
			}
			sort(ans , ans + cntt);
			for(int i=0;i<cntt;i++)
				printf("%d\n",ans[i]);
			printf("end\n");
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/flash403/article/details/94444171