晋城一中oj 议员秘密

【问题描述】

某国有N个议员,大佬XDD要从中选出来一部分一起喝茶谈一些事情。某两个议员之间可能存在矛盾,大佬XDD不希望选出来的这些议员之间有任何矛盾关系,以至于喝喝茶的场面搞得很尴尬。

已知这些议员之间存在M对矛盾关系,你能否帮助大佬XDD计算出他最多可以选出多少个议员来喝茶谈事情?

如果聪明的你把议员看成点,把矛盾关系看成无向边,那么题目中的数据保证M对矛盾所构成的图中不存在含有超过3个点的环。(图1符合要求,图2则不符合)

【输入数据】

输入文件的第一行是用空格隔开的两个整数N和M,表示一共有N个议员,这些议员之间有M对矛盾关系。接下来的M行,每行将有一对整数a和b(用空格隔开),表示议员a与议员b有矛盾。输入数据保证不含重边和自环。(议员的编号都是从1开始的)

【输出数据】

输出一行,包含一个整数,即大佬XDD最多可以选出多少议员来喝茶谈事情。

【输入输出样例】

secret.in

5 6

1 2

3 2

1 3

3 5

3 4

4 5

secret.out

2

【样例说明】

某国有6个议员,矛盾关系中1 - 2 - 3组成一个环,3 - 4 - 5组成一个环,因此只能在这两个环中分别选一个议员,并且不能选择3号议员。

【数据规模与约定】

对于20%的数据,1 ≤ N ≤ 20

对于40%的数据,1 ≤ N ≤ 50

对于100%的数据,1 ≤ N ≤ 200

输入数据保证合法。


【分析】
丫就是个树形dp…只不过有可能一个父节点的两个子节点相互矛盾…特判一下就好了
dp[u][0]代表不选u时的最多人数
dp[u][1]代表选u时的最多人数
注意一下…数据是森林…要不然会被坑掉20分


【代码】

#include<cstdio>
#include<iostream>
#include<cstring>
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=205;
int dp[mxn][2],dep[mxn],cun[mxn];   //1选 or 0不选 
int n,m,cnt;
bool con[mxn][mxn];
inline void dfs(int u,int fa)
{
    int i,j,v,cnt=0;
    int tmp[mxn];bool vis[mxn];
    memset(vis,0,sizeof vis);
    fo(v,1,n) if(v!=fa && con[u][v] && !dep[v]) dep[v]=dep[u]+1;
    fo(v,1,n) if(v!=fa && con[u][v] && dep[v]==dep[u]+1)
    {
        dep[v]=dep[u]+1;
        tmp[++cnt]=v;
        dfs(v,u);
    }
    fo(i,1,cnt)
    {
        fo(j,i+1,cnt)
        {
            int t1=tmp[i],t2=tmp[j];
            if(con[t1][t2])
            {
                dp[u][0]+=max(dp[t1][0]+dp[t2][0],max(dp[t1][1]+dp[t2][0],dp[t1][0]+dp[t2][1]));
                vis[t1]=vis[t2]=1;
                break;
            }
        }
    }
    fo(i,1,cnt)
    {
        v=tmp[i];
        dp[u][1]+=dp[v][0];
        if(vis[v]) continue;
        dp[u][0]+=max(dp[v][0],dp[v][1]);
    }
    dp[u][1]++;
}
int main()
{
//  freopen("input.txt","r",stdin);
//  freopen("output.txt","w",stdout);
    int i,j,u,v,ans=0;
    scanf("%d%d",&n,&m);
    while(m--)
    {
        scanf("%d%d",&u,&v);
        con[u][v]=con[v][u]=1;
    }
    fo(i,1,n)
      if(!dp[i][1])
      {
          dep[i]=1;
          dfs(i,0);
          cun[++cnt]=i;
      }
    fo(i,1,cnt) ans+=max(dp[cun[i]][0],dp[cun[i]][1]);
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值