zoukankan      html  css  js  c++  java
  • ZOJ3256 Tour in the Castle

    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:

    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
    ",st2);
    128 //                printf("st:%d j:%d u:%d v:%d
    ",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("
    ");
    140     }
    141     printf("fin
    ");
    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("
    ");
    152     }*/
    153     if(!bas.x[1][0])printf("Impossible
    ");
    154     else printf("%d
    ",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
    ");
    162             continue;
    163         }
    164         init();
    165         solve();
    166     }
    167     return 0;
    168 }
  • 相关阅读:
    解决Android的ListView控件滚动时背景变黑
    倒计时实现网页跳转
    java获取当前路径
    JavaScript笔记之面向对象
    Jqery调用WebService(.Net3.5环境下)
    Android开发:TabActivity中onKeyDown无法响应的解决方法
    最近不知道什么时候开始D3D11CreateDevice返回E_FAIL
    C++ allocator及一些影响程序性能的因素
    AOP切面编程 几年前写的,移过来
    Adaptive Transparency
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6647682.html
Copyright © 2011-2022 走看看