Problem Description
众所周知,度度熊非常喜欢图。
它最近发现了图中也是可以出现 valley —— 山谷的,像下面这张图。
为了形成山谷,首先要将一个图的顶点标记为高点或者低点。标记完成后如果一个顶点三元组<X, Y, Z>中,X和Y之间有边,Y与Z之间也有边,同时X和Z是高点,Y是低点,那么它们就构成一个valley。
度度熊想知道一个无向图中最多可以构成多少个valley,一个顶点最多只能出现在一个valley中。
Input
第一行为T,表示输入数据组数。
每组数据的第一行包含三个整数N,M,K,分别表示顶点个数,边的个数,标记为高点的顶点个数。
接着的M行,每行包含两个两个整数Xi,Yi,表示一条无向边。
最后一行包含K个整数Vi,表示这些点被标记为高点,其他点则都为低点。
● 1≤T≤20
● 1≤N≤30
● 1≤M≤N*(N-1)/2
● 0≤K≤min(N,15)
● 1≤Xi, Yi≤N, Xi!=Yi
● 1≤Vi≤N
Output
对每组数据输出最多能构成的valley数目。
Sample Input
3
3 2 2
1 2
1 3
2 3
3 2 2
1 2
1 3
1 2
7 6 5
1 2
1 3
1 4
2 3
2 6
2 7
3 4 5 6 7
Sample Output
1
0
2
——————————————————————————————————————————————————————————
果然状压dp不是很熟悉 比赛的时候没有想出来
f【i】【j】表示前i块石头 j及高点的情况
然后枚举两个高点就好辣
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=107,maxn=100010; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int T,n,m,k,now,ans,cnt; int h[M],v[M]; int f[2][maxn],map[M][M]; void clear(){ ans=0; cnt=1; memset(map,0,sizeof(map)); memset(f,0,sizeof(f)); memset(v,0,sizeof(v)); } int main() { T=read(); while(T--){ int x,y; n=read(); m=read(); k=read(); clear(); for(int i=1;i<=m;i++) x=read(),y=read(),map[x][y]=map[y][x]=1; for(int i=1;i<=k;i++) h[i]=read(),v[h[i]]=1; int s=(1<<k)-1; for(int i=1;i<=n;i++)if(!v[i]){ now=(++cnt)&1; memset(f[now],0,sizeof(f[now])); for(int j=0;j<=s;j++) f[now][j]=f[now^1][j]; for(int j=0;j<=s;j++){ for(int k1=1;k1<=k;k1++) if(!(j&(1<<(k1-1)))&&map[i][h[k1]]){ for(int k2=k1+1;k2<=k;k2++) if(!(j&(1<<(k2-1)))&&map[i][h[k2]]){ int nows=j^(1<<(k1-1))^(1<<(k2-1)); f[now][nows]=max(f[now][nows],f[now^1][j]+1); } } } } for(int i=0;i<=s;i++) ans=max(ans,f[now][i]); printf("%d ",ans); } return 0; }