题目:给出p1+p2个人,其中p1个是好人,p2个是坏人。然后有一些关系 ,a说b是好人(坏人).其中没有矛盾的,判断是否有唯一解判断哪些人是好人,哪些人是坏人。
其中比较重要的是,好人总说真话,坏人总说假话。不需要判断矛盾。唯一解
r表示与祖宗结点是否为同一阵营 0为同一阵营 1为不在同一阵营
通过并查集把所以点名分成多个集合 每个集合分成1 0两个阵营
然后DP判断每个集合中的0或者1是好人判断是否有唯一解
#include "stdio.h"
#include "map"
#include "queue"
#include "iostream"
#include "functional"
#include "math.h"
#include "algorithm"
using namespace std;
const int maxn = 1005;
const int mod = 1000000007 ;
const int inf = 1<<30;
typedef __int64 LL;
typedef pair<int,int> pii;
int k,n,m,tot;
int p[maxn],w[maxn];
int mark[maxn],vis[maxn];
int dp[maxn][maxn];
struct Node
{
int g,b;
}node[maxn];
int find( int x )
{
if( p[x] == x ) return x;
int tmp = p[x];
p[x] = find( p[x] );
w[x] = ( w[x]+w[tmp] )%2;
return p[x];
}
void merge( int a,int b,int g )
{
int x = find( a );
int y = find( b );
if( x != y )
{
p[x] = y;
w[x] = ( w[x] + w[a] - w[b] + g+ 4 )%2;
}
}
void GetDp()
{
memset( dp,0,sizeof(dp) );
dp[0][0] = 1;
for( int i = 1; i < tot; i ++ )
{
for( int j = 0; j <= n; j ++ )
{
if( dp[i-1][j] != 0 )
{
dp[i][j+node[i].b] += dp[i-1][j];
dp[i][j+node[i].g] += dp[i-1][j];
}
}
}
}
void fun()
{
int tmp = n;
memset( vis,0,sizeof(vis) );
for( int i = tot-1; i > 0; i -- )
{
if( dp[i-1][tmp-node[i].b] == 1 && node[i].b && dp[i-1][tmp-node[i].g] == 1 && node[i].g )
continue;
if( dp[i-1][tmp-node[i].b] == 1 && node[i].b )
{
vis[i] = 1;
tmp -= node[i].b;
}
else if( dp[i-1][tmp-node[i].g] == 1 && node[i].g )
{
vis[i] = 2;
tmp -= node[i].g;
}
}
}
void init()
{
tot = 1;
for( int i = 1; i <= n+m; i ++ )
{
p[i] = i; mark[i] = -1;
w[i] = 0;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("data.txt","r",stdin);
#endif
char str[10];
int a,b;
while( scanf("%d%d%d",&k,&n,&m) != EOF,( k||n||m ) )
{
init();
for( int i = 1; i <= k; i ++ )
{
scanf("%d%d%s",&a,&b,str);
merge( a,b,str[0]=='y'?0:1 );
}
for( int i = 1; i <= n+m; i ++ )
{
find( i );
}
for( int i = 1; i <= n+m; i ++ )
{
if( mark[p[i]] == -1 )
{
node[tot].b = node[tot].g = 0;
mark[p[i]] = tot ++;
}
w[i] == 1?node[mark[p[i]]].g ++:node[mark[p[i]]].b ++;
}
if( n == m )
puts("no");
else{
GetDp();
if( dp[tot-1][n] == 1 )
{
fun();
for( int i = 1; i <= n+m; i ++ )
{
if( vis[mark[p[i]]] == 2 && w[i] == 1 )
printf("%d\n",i);
else if( vis[mark[p[i]]] == 1 && w[i] == 0 )
printf("%d\n",i);
}
puts("end");
}
else
puts("no");
}
}
return 0;
}