題意:在圖中找簡單迴路
/*************看了大神的部落格才有所感悟啊,記憶化搜尋+狀態壓縮。。。。太神了...這種複雜度,近百萬的DFS複雜度居然沒有TLE,果然經驗不足,菜鳥一隻。用狀態壓縮枚舉起點和可能經過的點。可以判定的簡單通路 i->j,存在的條數為sum(i->k) 其中k,j之間有邊。當然,每次計算通路個數的時候,可以借每一個k來判斷迴路的條數,當然只能算一次。這樣加出來的迴路會有重複,因為可能把順逆兩種方向運動的迴路都考慮進去。記憶化搜尋的好處是可以精確的計算每次遍曆點的情況,而如果單純只是迴圈的話,卻沒有這麼靈活。****************/#define LL long long#include<cstdio>#include<cstring>const int LMT=22,LMS=1<<19;LL dp[LMS][LMT],ans;int n,start,tem,gra[LMT][LMT];int get_one(int x){ int res=0; do res+=x&1; while(x>>=1); return res;}int left(int x){ int d=x&(-x),res=0; while(d>>=1)res++; return res;}LL dfs(int mas,int end){ if(dp[mas][end]>=0)return dp[mas][end]; LL res=0; for(int j=start;j<n;j++) if(gra[j][end]&&((1<<j)&mas)&&(tem==2||j!=start)) { tem--; res+=dfs(mas^(1<<end),j); tem++; } if(tem>2&&gra[end][start]) ans+=res; dp[mas][end]=res; return res;}int main(void){ int m,lim; scanf("%d%d",&n,&m); memset(dp,-1,sizeof(dp)); while(m--) { int u,v; scanf("%d%d",&u,&v); u--;v--; gra[u][v]=gra[v][u]=1; } lim=1<<n; for(int i=0;i<n;i++)dp[1<<i][i]=1; for(int t=0;t<lim;t++) { start=left(t); tem=get_one(t); for(int j=start;j<n&&tem>1;j++) if(gra[j][start]&&((1<<j)&t)) dfs(t,j); } printf("%I64d\n",ans>>1); return 0;}