奇怪的道路[JXOI2012]
阿新 • • 發佈:2017-07-31
sample lose 偶數 dfs ostream led strong 順序 處理
題目描述
小宇從歷史書上了解到一個古老的文明。這個文明在各個方面高度發達,交通方面也不例外。考古學家已經知道,這個文明在全盛時期有n座城市,編號為1..n。m條道路連接在這些城市之間,每條道路將兩個城市連接起來,使得兩地的居民可以方便地來往。一對城市之間可能存在多條道路。
據史料記載,這個文明的交通網絡滿足兩個奇怪的特征。首先,這個文明崇拜數字K,所以對於任何一條道路,設它連接的兩個城市分別為u和v,則必定滿足1 <=|u - v| <= K。此外,任何一個城市都與恰好偶數條道路相連(0也被認為是偶數)。不過,由於時間過於久遠,具體的交通網絡我們已經無法得知了。小宇很好奇這n個城市之間究竟有多少種可能的連接方法,於是她向你求助。
方法數可能很大,你只需要輸出方法數模1000000007後的結果。
輸入
輸入共一行,為3個整數n,m,K。
輸出
輸出1個整數,表示方案數模1000000007後的結果。
提示
100%的數據滿足1<= n <= 30, 0 <= m <= 30, 1 <= K <= 8.
【題目說明】
兩種可能的連接方法不同當且僅當存在一對城市,它們間的道路數在兩種方法中不同。
在交通網絡中,有可能存在兩個城市無法互相到達。
樣例輸入
【輸入樣例1】
3 4 1
【輸入樣例2】
4 3 3
樣例輸出
【輸出樣例1】 3 【輸出樣例2】 4
【題解】
看到小數據居然也沒往狀壓上想,只是想打個表騙分,試試打表的可行性。然後寫了個dfs,放一邊打表,不過表打得不夠成功只搜出來1300+個結果,大概我在dfs裏搜索的順序還可以再好一些,人生第一次打表以25分圓滿結束~
這道題主要的限制是邊的兩端只能相差K,以及點的度必須為偶數。對於前者,采用回連的策略避免重復。對於後者,K只有8,將i-K到i的度的奇偶性壓成1維。 設f[i][j][k][l]表示考慮到點i,用了j條邊,i-K到i的奇偶性為k,當前處理i-K+l和i之間的連邊。 如果這條邊不連,可以轉移到f[i][j][k][l+1]. 如果這條邊連,可以轉移到f[i][j+1][k^(1<<K)^(1<<l)][l].(這裏的亦或相當於改變奇偶性,註意j+1<=m&&i-K+l>=1) 如果l=K並且i-K的度為偶數,可以轉移到f[i+1][j][k>>1][0]; 最後答案就是f[n+1][m][0][0];
模運算常數極大,適當減少模運算也是卡常的好辦法。
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int mod=1000000007; 5 int n,m,p,temp,f[35][35][(1<<9)+5][9]; 6 int main() 7 { 8 scanf("%d%d%d",&n,&m,&p); 9 temp=(1<<(p+1))-1; 10 f[1][0][0][0]=1; 11 for(int i=1;i<=n;i++) 12 for(int j=0;j<=m;j++) 13 for(int k=0;k<=temp;k++) 14 { 15 for(int l=0;l<p;l++) 16 if(f[i][j][k][l]) 17 { 18 f[i][j][k][l+1]=(f[i][j][k][l+1]+f[i][j][k][l])%mod; 19 if(j+1<=m&&i-p+l>=1) 20 f[i][j+1][k^(1<<p)^(1<<l)][l]=(f[i][j+1][k^(1<<p)^(1<<l)][l]+f[i][j][k][l])%mod; 21 } 22 if((!(k&1))&&f[i][j][k][p]) 23 f[i+1][j][k>>1][0]=f[i][j][k][p]%mod; 24 } 25 printf("%d",f[n+1][m][0][0]); 26 return 0; 27 }road
奇怪的道路[JXOI2012]