思路:
- 带权并查集(种类)
- 注意 par[i] 和 FIND(i) 的区别。
- dp+输出路径
- 注意cur卡了很久
- 最奇怪的就是maxn的大小,605、1005都会WA,1000、1111则AC。
代码:
#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;
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)
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){
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])
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;
}