题目链接:https://ac.nowcoder.com/acm/contest/885/E
又是一道水题没做,不过看题解时有地方想不太清楚。dp[i]表示i所代表的集合的最大独立子集的大小,随便从这个集合中取一个点x,dp[i]=max(dp[i^mi[x]],dp[i&e[x]]+1),e[x]表示与x都没有边的点的集合。之前想不太清楚为什么只要随便取一个点枚举。后来思考了一哈因为dp[i^mi[x]]是已经确定大小的,所以我们就只要考虑x丢不丢进i的最大独立集的集合中,丢进来,那么久只能是与x不相邻的那些店的最大独立子集的大小+1了。枚举别的点,和枚举x是等效的,因为在求dp[i^mi[x]]时,已经枚举了其他点,从小到大枚举,只要保证前面是对的,推到后面肯定是对的。。。完了这么水的dp也开始要想很久才能想清楚了。
#include<bits/stdc++.h>
using namespace std;
int n,m,sum;
int e[27],mi[27];
char dp[1<<26];
inline void prework()
{
scanf("%d%d",&n,&m);
int u,v;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
e[v]|=(1<<u);
e[u]|=(1<<v);
}
mi[0]=1;
for(int i=1;i<=n;i++)
mi[i]=mi[i-1]*2;
int s=(1<<n)-1;
for(int i=0;i<n;i++)
e[i]=s^(e[i]|mi[i]);
}
inline void mainwork()
{
int s=(1<<n)-1;
int x,id;
for(int i=1;i<=s;i++)
{
x=i&-i;id=log2(x);
dp[i]=max(dp[i^x],(char)(dp[i&e[id]]+1));
sum+=dp[i];
}
}
inline void print()
{
printf("%d",sum);
}
int main()
{
prework();
mainwork();
print();
return 0;
}