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 }
  • 相关阅读:
    0607pm克隆&引用类&加载类&面向对象串讲&函数重载
    0607am抽象类&接口&析构方法&tostring&小知识点
    静态
    面向对象--继承和多态
    面向对象的三个特性:封装
    ALV可输入状态下输入金额字段变小数的问题
    退出程序是跳过屏幕自检 比如 必输 EXIT-COMMAND
    ALV的报表对用户定义格式的控制(ALV I_SAVE)
    获利能力分析COPA的BAPI:BAPI_COPAACTUALS_POSTCOSTDATA 通过增强返回凭证号
    一个使用CDS VIEW 的 DEMO
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6647682.html
Copyright © 2011-2022 走看看