动规 插头DP 矩阵乘法
Time Limit: 5 Seconds      Memory Limit: 32768 KB

After the final BOSS is defeated, the hero found that the whole castle is collapsing (very familiar scene, isn't it). Escape from the castle is easy, just need to cross a few rooms. But as the Hero is full of adventurous spirit, he decides to visit every room before he escape the castle.

The castle is a rectangle with N * M rooms in it. Two rooms are connected if they share a common edge. The hero starts in the top left room. And the bottom left room is the only way out. After the hero visits a room and leaves it, it will collapse immediately(Another familiar scene). So he can visit each room only once.

The diagram shows one tour over a castle with 4 * 10 rooms:

ZOJ3256 Tour in the Castle_ios

Input

There are multiply cases (<20), process to the end of file.

Each case contains a line with two Integer N and M (2 <= N <= 7, 1 <= M <=10^9).

Ouput

For each case, if it's impossible to visit every room exactly once and get to the bottom left room, output "Impossible". Otherwise, output the number of tours as it describe above. Beacause the answer can be huge, you just need to output the answer MOD 7777777.

Sample Input

3 2
3 3
4 10

Sample Output

Impossible
2
2329

 

动态规划 插头DP 矩阵乘法 脑洞题

辣鸡破题蒸鹅心

问从起点到终点的哈密顿路径数(如图所示)

先把图顺时针旋转90°,再在最上面虚拟一行(这行只有最左边和最右边有向下插头), 显然这可以一行一行做插头DP。

但是由于行数太多了,会T。

普通DP会T的时候的优化方法之一是矩阵乘法,好巧这里就是用矩阵乘法。

将(旋转后的)一行设为一个状态,标记哪些位置有从上面来的插头

先暴力枚举判断出每个状态可以转移到哪些状态(合法状态最多130+种),然后建立转移矩阵,大力自乘到m次方,出解……

 

第一遍写了全程状态压位的普通写法,然后蜜汁爆炸调不对。挣扎好久之后放弃,从网上找到了神奇的数组记录插头的方法,看着直观又好写。

然后继续调错调错……

全程挣扎三个多小时

 

  1 /*by SilverN*/
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<cmath>
  7 #include<vector>
  8 #include<map>
  9 #define LL long long
 10 using namespace std;
 11 const int mod=7777777;
 12 const int mxn=100010;
 13 int read(){
 14     int x=0,f=1;char ch=getchar();
 15     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 16     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 17     return x*f;
 18 }
 19 int SZ,ed;
 20 int n,m;
 21 struct Mat{
 22     LL x[135][135];
 23     void init(){
 24         memset(x,0,sizeof x);
 25         for(int i=0;i<=SZ;i++)x[i][i]=1;
 26         return;
 27     }
 28     friend Mat operator * (Mat a,Mat b){
 29         Mat res;
 30         for(int i=0;i<=SZ;i++)
 31             for(int j=0;j<=SZ;j++){
 32                 res.x[i][j]=0;
 33                 for(int k=1;k<=SZ;k++)
 34                     res.x[i][j]+=a.x[i][k]*b.x[k][j];
 35                 res.x[i][j]%=mod;
 36             }
 37         return res;
 38     }
 39 }a,bas;
 40 map<int,int>mp;
 41 int cnt=0;
 42 int code[20];
 43 void decode(int x){
 44     for(int i=n;i;i--)code[i]=x&3,x>>=2;
 45 }
 46 int encode(){
 47     int w=0,ch[22];
 48     memset(ch,-1,sizeof ch);
 49     ch[0]=w++;
 50     int res=0;
 51     for(int i=1;i<=n;i++){
 52         if(ch[code[i]]==-1)ch[code[i]]=w++;
 53         code[i]=ch[code[i]];
 54         res=(res<<2)|code[i];
 55     }
 56     return res;
 57 }
 58 bool DP(int s,int T){
 59     decode(s);
 60     int left=0,cnt=0,k;
 61     for(int i=1;i<=n;i++){
 62         int v=T&(1<<(n-i));//当前位置有无上插头 
 63         if(!left){
 64             if(!code[i] && !v)return 0;
 65             if(!code[i] && v)left=-1;
 66             if(code[i] && !v)left=code[i];
 67             if(code[i] && v)continue;//竖线 
 68             k=i;
 69         }
 70         else{
 71             if(!code[i] && !v)continue;//
 72             else if(!code[i] && v){
 73                 if(left>0)code[k]=0,code[i]=left;//右+上 左+下 
 74                 else code[k]=code[i]=4+(cnt++);//右+下
 75                 left=0; 
 76             }
 77             else if(code[i] && !v){
 78                 if(code[i]==left && (T || i!=n))return 0;
 79                 if(left>0){//k 右+上 i 左+上 
 80                     for(int j=1;j<=n;j++){
 81                         if(code[j]==left)code[j]=code[i];
 82                     }
 83                     code[k]=code[i]=0;left=0;
 84                 }
 85                 else{
 86                     code[k]=code[i];
 87                     code[i]=0;
 88                     left=0;
 89                 }
 90             }
 91             else if(code[i] && v)return 0;
 92         }
 93     }
 94     return left==0;
 95 }
 96 void Calc(int k){
 97     bas.init();
 98     while(k){
 99         if(k&1)bas=bas*a;
100         a=a*a;
101         k>>=1;
102     }
103     return;
104 }
105 //map<int,int>::iterator it;
106 void init(){
107     memset(a.x,0,sizeof a.x);
108     memset(code,0,sizeof code);
109     mp.clear();//
110     code[1]=code[n]=1;
111     cnt=0;
112     ed=1<<n;
113     vector<int>v;
114     mp[0]=0;//目标状态 
115     mp[encode()]=++cnt;
116     v.push_back(0);
117     v.push_back(encode());
118     for(int i=1;i<v.size();i++){
119         int st=v[i];
120         for(int j=0;j<ed;j++){
121             if(DP(st,j)){
122                 int st2=encode();
123                 if(mp.find(st2)==mp.end()){
124                     mp[st2]=++cnt;
125                     v.push_back(st2);
126                 }
127 //                printf("st2:%d\n",st2);
128 //                printf("st:%d j:%d u:%d v:%d\n",st,j,i,mp[st2]);
129                 a.x[i][mp[st2]]=1;
130             }
131         }
132     }
133     SZ=cnt;
134 
135     for(int i=0;i<=SZ;i++){
136         for(int j=0;j<=SZ;j++){
137             printf("%d ",a.x[i][j]);
138         }
139         printf("\n");
140     }
141     printf("fin\n");
142 
143     return;
144 }
145 void solve(){
146     Calc(m);
147 /*    for(int i=0;i<=SZ;i++){
148         for(int j=0;j<=SZ;j++){
149             printf("%d ",bas.x[i][j]);
150         }
151         printf("\n");
152     }*/
153     if(!bas.x[1][0])printf("Impossible\n");
154     else printf("%d\n",bas.x[1][0]);
155     return;
156 }
157 int main(){
158     int i,j;
159     while(scanf("%d%d",&n,&m)!=EOF){
160         if((m&1)==0 && (n&1)){
161             printf("Impossible\n");
162             continue;
163         }
164         init();
165         solve();
166     }
167     return 0;
168 }

 

本文为博主原创文章,转载请注明出处。