poj 1417 并查集+dp

转自:点我

题目:给出p1+p2个人,其中p1个是好人,p2个是坏人。然后有一些关系 ,a说b是好人(坏人).其中没有矛盾的,判断是否有唯一解判断哪些人是好人,哪些人是坏人。

其中比较重要的是,好人总说真话,坏人总说假话。不需要判断矛盾。唯一解

http://poj.org/problem?id=1417

其中好人说真话,坏人说假话这点很重要。

那么如果一个人说另一个人是好人,那么如果这个人是好人,说明 对方确实是好人,如果这个是坏人,说明这句话是假的,对方也是坏人。

如果一个人说另一个人是坏人,那么如果这个人是好人,说明对方是坏人,如果这个是坏人,说明 对方是好人。

也就是如果条件是yes说明这两个是相同集合的,否则是两个不同的集合。

用r[i]表示i结点与根结点的关系,0为相同集合,1为不同集合。这是一个经典的并查集问题。

这样处理之后,还需要判断是否唯一

我们通过并查集,可以将所有人分为若干个集合,其中对于每一个集合,又分为两个集合(好人和坏人,但是不知道哪些是好人,哪些是坏人,我们只有相对关系)

接下来就是从所有大集合中的两个小集合取一个,组成好人集合,判断是否唯一。

背包问题,dp[i][j]表示前i个大集合,好人为j个的方案有多少种,或者dp[i][j]表示当前好人i个,坏人j个的情况有多少种

如果dp[cnt][p1]!=1说明方案不唯一,或者无解。

如果为1题目还需要输出方案,这点比较纠结。用后一种DP的时候WA了好多次,而这题又卡内存,不能开三维数组,其实可以两次DP解决。

后来采用前者DP,不断从dp[cnt][p1]往前递推,递推的结果也必须是某个前趋状态的dp值为1.

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<map>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<vector>
  7 #include<algorithm>
  8 #include<set>
  9 #include<string>
 10 #include<queue>
 11 #define inf 1<<30
 12 #define M 60005
 13 #define N 605
 14 #define maxn 300005
 15 #define pb(a) push_back(a)
 16 #define mem(a,b) memset(a,b,sizeof(a))
 17 using namespace std;
 18 int pre[N],r[N];
 19 int p1,p2,p;
 20 bool vis[N];
 21 int dp[N][N/2];
 22 int cnt;   //最后分为几个集合
 23 int a[N][2];  //a[i][0],a[i][1]分别表示把第i个集合分成的两个部分
 24 vector<int> b[N][2];
 25 int find(int x)
 26 {
 27     if(x!=pre[x])
 28     {
 29         int f=pre[x];
 30         pre[x]=find(pre[x]);
 31         r[x]=r[x]^r[f];
 32     }
 33     return pre[x];
 34 }
 35 void Init()
 36 {
 37     for(int i=1; i<=p1+p2; i++) pre[i]=i,r[i]=0;
 38     mem(vis,false);
 39     cnt=1;
 40     mem(a,0);
 41     for(int i=0; i<N; i++)
 42     {
 43         b[i][0].clear();
 44         b[i][1].clear();
 45     }
 46 }
 47 int main()
 48 {
 49     while(scanf("%d%d%d",&p,&p1,&p2)!=EOF&&p+p1+p2)
 50     {
 51         Init();
 52         while(p--)
 53         {
 54             int u,v;
 55             char str[10];
 56             scanf("%d%d%s",&u,&v,str);
 57             int k=(str[0]==‘n‘);
 58             int ra=find(u),rb=find(v);
 59             if(ra!=rb)
 60             {
 61                 pre[ra]=rb;
 62                 r[ra]=r[u]^r[v]^k;
 63             }
 64         }
 65         for(int i=1; i<=p1+p2; i++)
 66         {
 67             if(!vis[i])
 68             {
 69                 int f=find(i);
 70                 for(int j=i; j<=p1+p2; j++)
 71                 {
 72                     if(find(j)==f)
 73                     {
 74                         vis[j]=true;
 75                         b[cnt][r[j]].pb(j);
 76                         a[cnt][r[j]]++;
 77                     }
 78                 }
 79                 cnt++;
 80             }
 81         }
 82         mem(dp,0);
 83         dp[0][0]=1;
 84         for(int i=1; i<cnt; i++)
 85         {
 86             for(int j=p1; j>=0; j--)
 87             {
 88                 if(j-a[i][0]>=0)
 89                     dp[i][j]+=dp[i-1][j-a[i][0]];
 90                 if(j-a[i][1]>=0)
 91                     dp[i][j]+=dp[i-1][j-a[i][1]];
 92             }
 93         }
 94         if(dp[cnt-1][p1]!=1)
 95         {
 96             printf("no\n");
 97             continue;
 98         }
 99         else
100         {
101             vector<int>ans;
102             ans.clear();
103             for(int i=cnt-1; i>=1; i--)
104             {
105                 if(p1-a[i][0]>=0&&p2-a[i][1]>=0&&dp[i-1][p1-a[i][0]]==1)
106                 {
107                     for(int j=0; j<b[i][0].size(); j++)
108                     {
109                         ans.pb(b[i][0][j]);
110                     }
111                     p1-=a[i][0];
112                     p2-=a[i][1];
113                 }
114                 else if(p1-a[i][1]>=0&&p2-a[i][0]>=0&&dp[i-1][p1-a[i][1]]==1)
115                 {
116                     for(int j=0; j<b[i][1].size(); j++)
117                     {
118                         ans.pb(b[i][1][j]);
119                     }
120                     p1-=a[i][1];
121                     p2-=a[i][0];
122                 }
123             }
124             sort(ans.begin(),ans.end());
125             for(int i=0; i<ans.size(); i++) printf("%d\n",ans[i]);
126             printf("end\n");
127         }
128     }
129     return 0;
130 }
时间: 2024-10-12 20:34:14

poj 1417 并查集+dp的相关文章

poj1417(种类并查集+dp)

题目:http://poj.org/problem?id=1417 题意:输入三个数m, p, q 分别表示接下来的输入行数,天使数目,恶魔数目: 接下来m行输入形如x, y, ch,ch为yes表示x说y是天使,ch为no表示x说y不是天使(x, y为天使,恶魔的编号,1<=x,y<=p+q):天使只说真话,恶魔只说假话: 如果不能确定所有天使的编号,输出no,若能确定,输出所有天使的编号,并且以end结尾: 注意:可能会有连续两行一样的输入:还有,若x==y,x为天使: 思路:种类并查集+

POJ 2524 并查集

Ubiquitous Religions Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 23580 Accepted: 11609 Description There are so many different religions in the world today that it is difficult to keep track of them all. You are interested in finding o

真正的骗子(并查集+dp+dp状态回溯)

[//]: # (推荐题解模板,请替换blablabla等内容 ^^) ### 题目描述 一个岛上存在着两种居民,一种是天神,一种是恶魔. 天神永远都不会说假话,而恶魔永远都不会说真话. 岛上的每一个成员都有一个整数编号(类似于身份证号,用以区分每个成员). 现在你拥有n次提问的机会,但是问题的内容只能是向其中一个居民询问另一个居民是否是天神,请你根据收集的回答判断各个居民的身份. 输入格式 输入包含多组测试用例. 每组测试用例的第一行包含三个非负整数n,p1,p2p1,p2,其中n是你可以提问

POJ 1417 True Liars(并查集+DP)

大意: 一个岛上有神与恶魔两个种族,神会说真话,恶魔会说假话.已知神与恶魔的个数,但不知道具体个人是属于哪个. n,x,y 这个人问n次 ,x为神的个数,y为恶魔的个数. 每次的问题为 xi,yi,a 问xi ,yi是否为神? a为yes/no.注意xi,yi可能为同一个人 若最终可得出哪些是神则从小到大输出神的编号,并最终输出end 否则输出no 思路: 经过简单推理可得,只要是说yes,xi,yi为同一个族,no则不为同一个族. 这样通过使用并查集+relation(relation[i]为

poj 2513 并查集,Trie(字典树), 欧拉路径

- Colored Sticks POJ - 2513 You are given a bunch of wooden sticks. Each endpoint of each stick is colored with some color. Is it possible to align the sticks in a straight line such that the colors of the endpoints that touch are of the same color?

poj1417 true liars(并查集 + DP)详解

这个题做了两天了.首先用并查集分类是明白的, 不过判断是否情况唯一刚开始用的是搜索.总是超时. 后来看别人的结题报告, 才恍然大悟判断唯一得用DP. 题目大意: 一共有p1+p2个人,分成两组,一组p1个,一组p2个.给出N个条件,格式如下: x y yes表示x和y分到同一组 x y no表示x和y分到不同组 问分组情况是否唯一,若唯一则按从小到大顺序输出,否则输出no.保证不存在矛盾条件,但是有可能出现x=y的情况. 题目分析: 题中会给我们一些信息, 告诉我们那些是同一类, 哪些是不同类.

POJ 2492 并查集扩展(判断同性恋问题)

G - A Bug's Life Time Limit:10000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2492 Appoint description: Description BackgroundProfessor Hopper is researching the sexual behavior of a rare species of bugs. H

【POJ1417】【带标记并查集+DP】True Liars

Description After having drifted about in a small boat for a couple of days, Akira Crusoe Maeda was finally cast ashore on a foggy island. Though he was exhausted and despaired, he was still fortunate to remember a legend of the foggy island, which h

POJ 2492 并查集应用的扩展

A Bug's Life Time Limit: 10000MS Memory Limit: 65536K Total Submissions: 28651 Accepted: 9331 Description Background Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature two different genders and