【问题描述】

某国有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;
}