1. 程式人生 > >JZYZOJ 1388 旅遊 狀壓dp

JZYZOJ 1388 旅遊 狀壓dp

進行 tdi namespace 簡單 從後往前 ble con pan target

http://172.20.6.3/Problem_Show.asp?id=1388

求拓撲排序方案數 狀壓dp,最開始以為是拓撲排序加數論或者搜索,沒想到是狀壓dp,突然氣死.jpg; 完全沒有想到狀態轉移的方法,syq大佬太神了orz; 寫的時候太沈迷與topsort對人順序的分組類似於斯特林數求方案數(後來發現不是),忘了最原始的滿足條件(事件a在事件b前完成)即可增加方案數的簡單dp……(慚愧) 所以正解就是按dp進行順序向狀態裏加人,對人實現排序,顯然如果必須在a前的人都加到隊列裏了(我這裏用的是a後,嗯因為寫的時候是直接看syq大佬的代碼,其實我覺得記錄a前的更符合邏輯)那麽a就可以放到這個隊列後面了。
據此,f[i]表示狀態i(i上為1的位表示這一位的人放到隊列裏了)有多少種方案,a[x]表示x需要哪些人在前面(我寫的用的是後面,畢竟從後往前和從前往後並沒有什麽區別…)。 第一次交爆了long long,果然long long是1A率的攔路虎,努力克服 代碼 技術分享
 1 #include<iostream>  
 2 #include<cstdio>  
 3 #include<cstring>  
 4 #include<algorithm>  
 5 #include<cmath>
 6 #include<queue>
 7
using namespace std; 8 const int maxn=30; 9 int n,m; 10 int a[maxn]={}; 11 long long f[(1<<17)+10]={}; 12 int main(){ 13 scanf("%d%d",&n,&m);int x,y; 14 for(int i=1;i<=m;i++){ 15 scanf("%d%d",&x,&y); 16 a[x]|=(1<<(y-1)); 17 } 18 int ma=1
<<n;f[0]=1; 19 for(int i=1;i<ma;i++){ 20 for(int j=0;j<n;j++){ 21 if((1<<j)&i){ 22 y=i-(1<<j); 23 if((a[j+1]&(~y))==0){ 24 f[i]+=f[y]; 25 } 26 } 27 } 28 } 29 printf("%I64d\n",f[ma-1]); 30 return 0; 31 }
View Code

JZYZOJ 1388 旅遊 狀壓dp