zoukankan      html  css  js  c++  java
  • C

    思路:刚看这道题感觉什么都不清楚,人物之间的关系一点也看不出来,都不知道怎么写,连并查集都没看出来,但是你可以仔细分析一下,当输入字符串为“yes”的时候,我们设输入的值为x和y,当x为天使是则由题可知y也为天使;当x为魔鬼的时候,则y也为魔鬼,所以输入“yes”的时候就相当于说他们是同类。

    当输入字符串为“no”的时候,如果x为天使,则y为魔鬼;x为魔鬼的时候,y就是天使,所以当输入字符串为“no”的时候他们为异类。。这不就是种类并查集的

    0 (同类) 1(异类)并查集嘛!

    再接着想,通过并查集我们可以把它们分成两类,一种是和他们的根节点同类,一种不是同类。。这一点要注意了,所有的他们并不是一定是一个父节点,假如

    (1  2)(3  4) 那他们就不在一棵树上。。

    用完并查集我们就要用一个数组来记录他们根节点的数目,而且还要记录每一个根节点与其同类和异类的两种情况的数目,然后我们只要用这些数可以组合出来

    天使或魔鬼的数目就可以了,但是要保证只有一种方法可以,如果有好几种方法,那就无法确定。。还要注意的是当去组成天使或魔鬼的数目的时候,一个根节点只能选根节点的同类或异类来往上加,不能都选。。。

    上一点是不是有点像01背包,用一些数来组成一个数,看有几种方法

    最后就是输出路径(路径方法我之前写过,你也可以在网上搜一下)

    接着就上代码吧!

      1 //https://www.cnblogs.com/geloutingyu/p/6142473.html    我是看这个网址才懂得,可以看一下
      2 #include<stdio.h>
      3 #include<string.h>
      4 #include<iostream>
      5 #include<algorithm>
      6 using namespace std;
      7 int v[505],w[505],n,a,b,gg[505],jj[505][505],tag[505][2],dp[505][505],cc[505][2];
      8 struct shudui
      9 {
     10     int start,last;
     11     char q;
     12 }m[2005];
     13 int finds(int x)
     14 {
     15     if(x!=v[x])
     16     {
     17         int y=finds(v[x]);
     18         w[x]=(w[x]+w[v[x]])%2;
     19         v[x]=y;
     20         return y;
     21     }
     22     return x;
     23 }
     24 void join(int x,int y,int z)
     25 {
     26     int fx=finds(x);
     27     int fy=finds(y);
     28     if(fx==fy)
     29     {
     30         return;
     31     }
     32     else
     33     {
     34         v[fx]=fy;
     35         w[fx]=(2-w[x]+z-1+w[y])%2;
     36     }
     37 }
     38 int main()
     39 {
     40     while(~scanf("%d%d%d",&n,&a,&b))
     41     {
     42         memset(w,0,sizeof(w));
     43         if(n+a+b==0) break;
     44         for(int i=1;i<=a+b;++i)
     45         {
     46             v[i]=i;
     47         }
     48         while(n--)
     49         {
     50             char q[5];
     51             int x,y;
     52             scanf("%d%d%s",&x,&y,q);
     53             if(x==y)
     54                 continue;
     55             if(strcmp("no",q)==0)
     56             {
     57                 join(x,y,2);
     58             }
     59             else join(x,y,1);
     60         }
     61         //int w1[1005],w2[1005];
     62         memset(gg,0,sizeof(gg));    //存根节点
     63         memset(jj,0,sizeof(jj));
     64         memset(tag,0,sizeof(tag));  //来记录根节点同来和异类的数目
     65         memset(dp,0,sizeof(dp));    //背包dp,看看有几种方法
     66         memset(cc,0,sizeof(cc));    //标记,做最后输出
     67         int cnt=0;
     68         for(int i=1;i<=a+b;++i) //统计集合个数
     69         {
     70             if(finds(i)==i)
     71             {
     72                 gg[i]=++cnt;
     73             }
     74         }
     75         for(int i=1;i<=a+b;++i)
     76         {
     77             tag[gg[finds(i)]][w[i]]++;
     78         }
     79         dp[0][0]=1;
     80         for(int i=1;i<=cnt;++i)
     81         {
     82             for(int j=0;j<=a;++j)//dp[i][j]表示到第i个集合,人数达到j的方法数
     83             {
     84                 if(j-tag[i][0]>=0 && dp[i-1][j-tag[i][0]])
     85                 {
     86                     dp[i][j]+=dp[i-1][j-tag[i][0]];
     87                     jj[i][j]=tag[i][0];  //jj是记录路径的
     88                 }
     89                 if(j-tag[i][1]>=0 && dp[i-1][j-tag[i][1]])
     90                 {
     91                     dp[i][j]+=dp[i-1][j-tag[i][1]];
     92                     jj[i][j]=tag[i][1];
     93                 }
     94             }
     95         }
     96         if(dp[cnt][a]!=1)
     97         {
     98             printf("no
    ");
     99         }
    100         else
    101         {
    102             for(int i=cnt,j=a;j>0 && i>0; i--)
    103             {
    104                 if(jj[i][j]==tag[i][0])
    105                     cc[i][0]=1;
    106                 else cc[i][1]=1;
    107                 j-=jj[i][j];
    108             }
    109             for(int i=1;i<=a+b;++i)
    110             {
    111                 if(cc[gg[finds(i)]][w[i]]) printf("%d
    ",i);
    112             }
    113             printf("end
    ");
    114         }
    115     }
    116     return 0;
    117 }
    View Code
  • 相关阅读:
    paramiko
    Oracle 正则
    格式化输出
    pl/sql
    logging-----日志模块
    linux学习笔记01
    PHP-HTML-MYSQL表格添加删除
    费了好大劲做的比较好看的表单
    HTML框架
    两天笔记
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/10693368.html
Copyright © 2011-2022 走看看