1. 程式人生 > 實用技巧 >E - Boboniu Walks on Graph (列舉雜湊)

E - Boboniu Walks on Graph (列舉雜湊)

題:https://codeforces.com/contest/1395/problem/E

題意:給定n個點m條邊的圖,給定k,每個點的出度不會超過k,定義k個元素的ci陣列:對於每個節點度數di,那麼節點 i 要走第cdi小邊權的邊。對於圖上的每個點作為起點進行若干步ci陣列操作都能回到起點,問這樣的ci陣列有多少個。

分析:由於1<=k<=9&&1<=ci<=i,那麼最多有9!種ci陣列,即我們可以通過列舉來判斷其是否滿足條件。

   其實我們只要考慮每個點的下一個點會到哪個點即可,那麼要求每個點出發都能回到原點的條件就轉化為每個點的下一個點組成的點集為1~n(1到n恰好都只出現一次)。

   那麼我們考慮用雜湊值來表示點集,對於每個度數值有若干個點,累加每個第 i 小值節點對應的雜湊值;

   因為雜湊值的計算滿足結合律,所以直接把列舉的ci陣列的雜湊值與1~n和雜湊值比較即可完成判斷。

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define MP make_pair
const int M=2e5+5;
const int H=1e9+7;
vector
<pii >g[M]; ull goal,a[20][20],Hash[M]; int n,m,k,ans; void dfs(int u,ull now){ if(u==k+1){ ans+=(now==goal); return ; } for(int i=1;i<=u;i++) dfs(u+1,now+a[u][i]); } int main(){ scanf("%d%d%d",&n,&m,&k); for(int u,v,w,i=1;i<=m;i++){ scanf(
"%d%d%d",&u,&v,&w); g[u].pb(MP(w,v)); } Hash[0]=1,goal=0; for(int i=1;i<=n;i++){ Hash[i]=Hash[i-1]*H; goal+=Hash[i]; } for(int i=1;i<=n;i++){ sort(g[i].begin(),g[i].end()); int tot=g[i].size(); for(int j=0;j<tot;j++) a[tot][j+1]+=Hash[g[i][j].second]; } ans=0; dfs(1,0); printf("%d\n",ans); return 0; }
View Code