zoukankan      html  css  js  c++  java
  • POJ 1417 True Liars

    题意:有两种人,一种人只会说真话,另一种人只会说假话。只会说真话的人有p1个,另一种人有p2个。给出m个指令,每个指令为a b yes/no,意思是,如果为yes,a说b是只说真话的人,如果为no,a说b是只说假话的人。注意,a可以为b。保证每个指令都是正确的,且相互之间不矛盾。问,能不能确定哪些人是说真话的人,如果能,输出所有只说真话的人;如果不能,输出no。

    解法:首先,用并查集建树,每个节点有两个参数,f和r,f表示父亲节点的编号,r表示与父亲节点是不是同一种人。r为0表示该节点与父亲节点是一种人,r为1表示该节点与父亲节点不是一种人。则用并查集处理之后,就可以分为k棵树,每棵树上可能有x[i]个人是同一种人,y[i]个是另一种人,(不确定哪个是说真话人的数量,哪个是说假话的人的数量),且每棵树之间互不影响。所以即是一个背包问题,用dp解决即可。

    tag:并查集,DP,背包

      1 /*
      2  * Author:  Plumrain
      3  * Created Time:  2013-11-28 10:26
      4  * File Name: DS-POJ-1417.cpp
      5  */
      6 #include <iostream>
      7 #include <cstdio>
      8 #include <cstring>
      9 #include <algorithm>
     10 #include <vector>
     11 #include <map>
     12 
     13 using namespace std;
     14 
     15 #define CLR(x) memset(x, 0, sizeof(x))
     16 #define CLR1(x) memset(x, -1, sizeof(x))
     17 #define PB push_back
     18 typedef pair<int, int> pii;
     19 
     20 struct oo{
     21     int a, b, pos;
     22     void clr(){
     23         a = 0; b = 0;
     24     }
     25 };
     26 
     27 struct node{
     28     int f, r;
     29 };
     30 
     31 node p[5005];
     32 pii num[5005];
     33 vector<int> ans;
     34 oo cnt[5005];
     35 map<int, int> mp;
     36 int n, m, p1, p2, d[1205][1205];
     37 
     38 int find(int x)
     39 {
     40     if (x != p[x].f){
     41         int y = p[x].f;
     42         p[x].f = find(p[x].f);
     43         p[x].r = (p[x].r + p[y].r) % 2;
     44     }
     45     return p[x].f;
     46 }
     47 
     48 void merge(int a, int b, int x, int t1, int t2)
     49 {
     50     p[t1].f = t2;
     51     p[t1].r = (p[a].r + p[b].r + x) % 2;
     52 }
     53 
     54 void init()
     55 {
     56     for (int i = 0; i <= n; ++ i)
     57         cnt[i].clr();
     58 
     59     for (int i = 0; i <= n; ++ i){
     60         p[i].f = i;
     61         p[i].r = 0;
     62     }
     63     
     64     int a, b, x;
     65     char s[10];
     66     for (int i = 0; i < m; ++ i){
     67         scanf ("%d%d%s", &a, &b, s);
     68         if (s[0] == 'y') x = 0;
     69         else x = 1;
     70 
     71         int t1 = find(a), t2 = find(b);
     72         if (t1 != t2)
     73             merge(a, b, x, t1, t2);
     74     }
     75 }
     76 
     77 void gao0()
     78 {
     79     if (p2 == 0 || p1 == 0){
     80         for (int i = 1; i <= p1; ++ i)
     81             printf ("%d
    ", i);
     82         printf ("end
    ");
     83         return;
     84     }
     85     printf ("no
    ");
     86 }
     87 
     88 int main()
     89 {
     90     while (scanf ("%d%d%d", &m, &p1, &p2) != EOF){    
     91         if (!m && !p1 && !p2) break;
     92 
     93         if (!m){
     94             gao0();
     95             continue;
     96         }
     97 
     98         n = p1 + p2;
     99         init();
    100 
    101         if (p1 == p2){
    102             printf ("no
    ");
    103             continue;
    104         }
    105 
    106         CLR (num);
    107         for (int i = 1; i <= n; ++ i){
    108             int y = find(i);
    109             if (!p[i].r) ++ num[y].first;
    110             else ++ num[y].second;
    111         }
    112 
    113         int all = 1;
    114         for (int i = 1; i <= n; ++ i)
    115             if (num[i].first + num[i].second){
    116                 cnt[all].a = num[i].first;
    117                 cnt[all].b = num[i].second;
    118                 cnt[all].pos = i;
    119                 ++ all;
    120             }
    121 
    122         CLR1 (d);
    123         d[0][0] = 1;
    124         for (int i = 1; i < all; ++ i)
    125             for (int j = 0; j <= p1; ++ j){
    126                 if (j >= cnt[i].a && d[i-1][j-cnt[i].a] >= 0){
    127                     if (d[i][j] == -1) d[i][j] = 0;
    128                     d[i][j] += d[i-1][j-cnt[i].a];
    129                 }
    130                 if (j >= cnt[i].b && d[i-1][j-cnt[i].b] >= 0){
    131                     if (d[i][j] == -1) d[i][j] = 0;
    132                     d[i][j] += d[i-1][j-cnt[i].b];
    133                 }
    134             }
    135 
    136         if (d[all-1][p1] != 1) printf ("no
    ");
    137         else{
    138             int j = p1;
    139             mp.clear();
    140             for (int i = all-1; i; -- i){
    141                 if (j >= cnt[i].a && d[i-1][j-cnt[i].a] == 1){
    142                     j -= cnt[i].a;
    143                     mp[cnt[i].pos] = 0;
    144                 }
    145                 else if (j >= cnt[i].b && d[i-1][j-cnt[i].b] == 1){
    146                     j -= cnt[i].b;
    147                     mp[cnt[i].pos] = 1;
    148                 }
    149             }
    150 
    151             ans.clear();
    152             for (int i = 1; i <= n; ++ i){
    153                 int y = find(i);
    154                 if (mp.count(y) && mp[y] == p[i].r)
    155                     ans.PB (i);
    156             }
    157             
    158             sort(ans.begin(), ans.end());
    159             int sz = ans.size();
    160             for (int i = 0; i < sz; ++ i)
    161                 printf ("%d
    ", ans[i]);
    162             printf ("end
    ");
    163         }
    164 
    165     }
    166     return 0;
    167 }
    View Code
    ------------------------------------------------------------------
    现在的你,在干什么呢?
    你是不是还记得,你说你想成为岩哥那样的人。
  • 相关阅读:
    导出报ora-31634、ora-31664
    A significant part of sql server process memory has been paged out
    解决ora-02429:无法用于删除强制唯一/主键的索引
    更改数据库表中有数据的字段类型NUMERIC(18,2)为NUMERIC(18,6)
    GHOST CLEANUP Process
    oracle查看执行计划explain plan FOR
    ORA-01502: 索引或这类索引的分区处于不可用状态
    mysql 游标循环,嵌套游标循环
    MSSQL FOR XML PATH ('')用法
    Mysql CHARINDEX用法
  • 原文地址:https://www.cnblogs.com/plumrain/p/POJ_1417.html
Copyright © 2011-2022 走看看