1. 程式人生 > >奇怪的道路[JXOI2012]

奇怪的道路[JXOI2012]

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]