垃圾状压dp,应该根本没有紫题难度
设当前状态为state,起点为state包含的元素中最小的一个,防止重复,以及当前所在地点u
注意自环,就是两个点来回走的。在答案里修改也可以。我是直接在ans更新时判断state是否合法,是否包含至少3个元素
然后一个答案会两种时针方式走,所以最终答案要处以2
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll f[20][600005]={0},ans=0; int n,m; int hed[5005],tal[5005],nxt[5005],cnt=0; inline void addege(int x,int y){ cnt++; tal[cnt]=y; nxt[cnt]=hed[x]; hed[x]=cnt; } bool ck(int state){ int cnt=0; for(int i=1;i<=n;i++){ if((state&(1<<(i-1)))==(1<<(i-1))){ cnt++; } } if(cnt<=2) return 0; return 1; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); addege(x,y); addege(y,x); } for(int i=1;i<=n;i++){ f[i][1<<(i-1)]=1ll; } for(int state=1;state<(1<<n);state++){ int st,u; for(int i=1;i<=n;i++){ if((state&(1<<(i-1)))==(1<<(i-1))){ st=i; break; } } for(int i=1;i<=n;i++){ if((state&(1<<(i-1)))!=(1<<(i-1))) continue; u=i; for(int j=hed[u];j;j=nxt[j]){ int v=tal[j]; if(v<st) continue; if((state&(1<<(v-1)))==(1<<(v-1))){ if(v==st&&ck(state)) ans+=f[u][state]/*printf("st:%d,state:%d,f[u][state]:%d\n",st,state,f[u][state])*/; } else f[v][state|(1<<(v-1))]+=f[u][state]; } } } cout<<ans/2<<endl; return 0; }