小宇從歷史書上了解到一個古老的文明。這個文明在各個方面高度發達,交通方面也不例外。考古學家已經知道,這個文明在全盛時期有n座城市,編號爲1..n。m條道路鏈接在這些城市之間,每條道路將兩個城市鏈接起來,使得兩地的居民能夠方便地來往。一對城市之間可能存在多條道路。
據史料記載,這個文明的交通網絡知足兩個奇怪的特徵。首先,這個文明崇拜數字K,因此對於任何一條道路,設它鏈接的兩個城市分別爲u和v,則一定知足1 <=|u - v| <= K。此外,任何一個城市都與剛好偶數條道路相連(0也被認爲是偶數)。不過,因爲時間過於久遠,具體的交通網絡咱們已經沒法得知了。小宇很好奇這n個城市之間究竟有多少種可能的鏈接方法,因而她向你求助。
方法數可能很大,你只須要輸出方法數模1000000007後的結果。php
輸出1個整數,表示方案數模1000000007後的結果。
網絡
100%的數據知足1
<= n <= 30, 0 <= m <= 30, 1 <= K <= 8.
【題目說明】
兩種可能的鏈接方法不一樣當且僅當存在一對城市,它們間的道路數在兩種方法中不一樣。
在交通網絡中,有可能存在兩個城市沒法互相到達。spa
能夠把圖中的點當作一列數,在這列數中連邊,搞DP。
對於c < k,若連邊,則能夠轉移到f(i, j + 1, s', k);若不連邊,則能夠轉移到f(i, j, s, k + 1)。
對於c = k,只有當i - k的度爲偶數才能夠轉移到f(i + 1, j, s', 0)。
時間複雜度O(NMK * 2^K)。
比較難理解,具體看代碼:
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int mod=1000000007;
4 inline int read(){
5 int x=0,f=1;char ch=getchar();
6 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
7 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
8 return x;
9 }
10 int N,M,K;
11 int f[35][35][1025][9];//f[i][j][s][c]表示處理到第i個點,共用j條邊,
12 //第三維表示(i-k)~i這些點度的奇偶性爲二進制數s,0表示偶數,1表示奇數
13 //當前處理的連邊爲(i,i-k+c)的方案數。
14 int main(){
15 N=read(),M=read(),K=read();
16 f[2][0][0][0]=1;
17 for(int i=2;i<=N;++i){//枚舉第i個點
18 for(int j=0;j<=M;++j){//已經連了j條邊
19 for(int s=0;s<(1<<(K+1));++s){//0~2^(l+1)-1 包含i自己
20 for(int c=0;c<K;++c){// i ~ i-k+c
21 if(f[i][j][s][c]!=0){//f[i][j][s][c]!=0來更新其餘值,刷表法
22 f[i][j][s][c+1]+=f[i][j][s][c]%mod;//此時不連邊可直接轉移
23 f[i][j][s][c+1]%=mod;
24 if(j<M&&i-K+c>=1){
25 f[i][j+1][s^(1<<K)^(1<<c)][c]+=f[i][j][s][c]%mod;
26 f[i][j+1][s^(1<<K)^(1<<c)][c]%=mod;
27 //K與c之間連一條邊,其實K表示的是第i個點,c表示的是i-K+c個點,只是根據反向對稱性反過來不影響答案
28 //s^(1<<K)^(1<<c),使 1<<K,1<<c的位置的奇偶性取反
29 }
30 }
31 }
32 if((s&1)==0&&f[i][j][s][K]!=0) f[i+1][j][s>>1][0]=f[i][j][s][K];//第i個點連了偶數條邊能夠直接給 i+1,
33 //s>>1至關於除掉了第i個點
34 }
35 }
36 }
37 printf("%d",f[N+1][M][0][0]);
38 return 0;
39 }