标签:
| Time Limit: 1000MS | Memory Limit: 10000K | |
| Total Submissions: 2221 | Accepted: 685 |
Description
Input
Output
Sample Input
2 1 1 1 2 no 2 1 no 3 2 1 1 1 yes 2 2 yes 3 3 yes 2 2 1 1 2 yes 2 3 no 5 4 3 1 2 yes 1 3 no 4 5 yes 5 6 yes 6 7 no 0 0 0
Sample Output
no no 1 2 end 3 4 5 6 end
分析:题意:在一个孤岛上有两个部落,一个部落都是好人,一个部落都是坏人,好人都说真话,坏人
都说假话。有一群人来自两个部落,通过给定的数据确定那些是好人,且以升序输出。
这道题有一点需要注意:好人说真话,如果一个人是好人,他说另一个人是坏人这这个人一定是坏人,否则
这个人一定是好人;相反,如果一个人是坏人,他说另一个人是坏人则这个人一定是好人,否则这个人一定
是坏人。另外要记住在这里面好人坏人是相对的,也就是说我们只能判断谁和谁同等人,即yes带表同等集合
no表示相反集合。
这道题我们要最终把这一群人分成若干集合(一颗树就是一个集合,一群人是一个森林),然后每一个集合分成
朋友,敌人两个子集a和b(大家不要误解朋友集合和敌人集合的意思,它们是通过并查集确定的两个集合,在这两个集合中
必有一个集合为好人,一个集合为坏人,只不过我们现在还不确定是好谁坏)。这个用并查集可以不难做到。难点是一下:
因为题目已经告诉好人坏人的个数,因此我们从这若干个集合中每个集合挑出一个子集,是这些子集之和等于好人
数目p1,判断这样的情况有多少种,如果答案唯一则可以确定那些事好人,那些是坏人了,因此需要用
到动态规划中的背包一类。
设数组dp【maxn】【maxn】,dp【i】【j】代表到第i个集合好人数为j的情况数; 状态转移方程为:
dp【i】【j】=dp【i-1】【j-a】+dp【i-1】【j-a】;
如果dp【cnt】【p1】==1说明情况唯一(cnt为集合数),则可一找出好人个数;
由于小生是dp学的不好所以猥琐看了某君dp代码,其中有一句:点dp【i】【j】>1时我都是dp【i】【j】=2;
以为算到最后如果dp【cnt】【p1】>1就无解,所以dp【i】【j】>1就行。
唉,必须好好学啊,加油。
献上代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=600+10;
int fa[maxn],level[maxn],id[maxn];
int dp[maxn][maxn],ans[maxn][maxn],map[maxn][2],num[maxn][2];
void Init(int snum)
{
for(int i=0;i<=snum;i++)
{
fa[i]=i;
}
memset(dp,0,sizeof(dp));
memset(level,0,sizeof(level));
memset(ans,0,sizeof(ans));
memset(map,0,sizeof(map));
memset(num,0,sizeof(num));
memset(id,0,sizeof(id));
}
int find(int x)
{
if(x!=fa[x])
{
int tmp=fa[x];
fa[x]=find(fa[x]);
level[x]=level[x]^level[tmp];
}
return fa[x];
}
int main()
{
int n,p1,p2,x,y,fx,fy,cnt;
char c[10];
while(~scanf("%d%d%d",&n,&p1,&p2)&&(n+p1+p2))
{
Init(p1+p2);
for(int i=0;i<n;i++)
{
scanf("%d%d%s",&x,&y,c);
fx=find(x);
fy=find(y);
if(fx==fy)
continue;
fa[fy]=fx;
if(c[0]==‘y‘)
{
level[fy]=level[x]^level[y]^0;
}
else
{
level[fy]=level[x]^level[y]^1;
}
}
cnt=0;
for(int i=1;i<=p1+p2;i++)
if(find(i)==i)id[i]=++cnt;
for(int i=1;i<=p1+p2;i++)
{
map[id[find(i)]][level[i]]++;
}
dp[0][0]=1;
for(int i=1;i<=cnt;i++)
for(int j=0;j<=p1+p2;j++)
{
if(j>=map[i][0]&&dp[i-1][j-map[i][0]]>0)
{
dp[i][j]+=dp[i-1][j-map[i][0]];
ans[i][j]=map[i][0];
}
if(j>=map[i][1]&&dp[i-1][j-map[i][1]]>0)
{
dp[i][j]+=dp[i-1][j-map[i][1]];
ans[i][j]=map[i][1];
}
if(dp[i][j]>1)
dp[i][j]=2;
}
if(dp[cnt][p1]!=1)
{
printf("no\n");
continue;
}
for(int i=cnt,j=p1;i>=1;i--)
{
if(map[i][0]==ans[i][j])num[i][0]=1;
else num[i][1]=1;
j-=ans[i][j];
}
for(int i=1;i<=p1+p2;i++)
{
if(num[id[find(i)]][level[i]])
printf("%d\n",i);
}
printf("end\n");
}
return 0;
}
标签:
原文地址:http://blog.csdn.net/letterwuyu/article/details/45179787