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 }
  • 相关阅读:
    在实践中培养学生学习软件工程的兴趣
    软件工程课程设计指导随笔
    软件工程——个人总结
    软件工程第二次作业——结对编程
    个人博客作业三:微软小娜APP的案例分析
    嵌入式软件设计第12次实验报告
    嵌入式软件设计第11次实验报告
    嵌入式软件设计第09实验报告
    嵌入式软件设计第10次实验报告
    嵌入式软件设计第7次实验报告8
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6647682.html
Copyright © 2011-2022 走看看