zoukankan      html  css  js  c++  java
  • URAL 1519 Formula 1

    题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1519

    陈丹琦的《基于连通性状态压缩的动态规划问题》的论文上的题目

    题意:

    给你m*n的棋盘,有的格子是障碍,问共有多少条回路使得经过每个非障碍格子恰好一次。

    做法:

    论文上的思路讲的很清楚了,这里用最小表示法来做。

    因为(2 ≤ NM ≤ 12),所以最多出现6个联通块,所以用8进制来做。

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 int N, M;
      4 #define maxn 15
      5 #define HASH 30007
      6 #define STATE 200010
      7 int mp[maxn][maxn];
      8 int pos[maxn];
      9 int mark, ex, ey;
     10 int code[maxn];
     11 struct HashMap
     12 {
     13     int head[HASH], next[STATE], cnt;
     14     long long state[STATE];
     15     long long sum[STATE];
     16     void init()
     17     {
     18         cnt = 0;
     19         memset(head, -1, sizeof(head));
     20     }
     21     void push(long long sta, long long val)
     22     {
     23         int h = sta%HASH;
     24         for(int i = head[h]; i != -1; i = next[i])
     25         {
     26             if(state[i] == sta)  //如果这种状态已经存在
     27             {
     28                 sum[i] += val;
     29                 return;
     30             }
     31         }
     32         state[cnt] = sta;
     33         sum[cnt] = val;
     34         next[cnt] = head[h];
     35         head[h] = cnt++;
     36     }
     37 }hashmp[2];//滚动数组
     38 void decode(int *code, long long sta)  
     39 {
     40     for(int i = M; i >= 0; i--)
     41     {
     42         code[i] = sta&7;
     43         sta >>= 3;
     44     }
     45 }
     46 long long encode(int *code) //转化成2进制
     47 {
     48     int cnt = 1;
     49     int vis[maxn];
     50     memset(vis, -1, sizeof(vis));
     51     vis[0] = 0;  //0不连通
     52     long long sta = 0;
     53     
     54     for(int i = 0; i <= M; i++)
     55     {
     56         if(vis[code[i]] == -1) vis[code[i]] = cnt++;
     57         code[i] = vis[code[i]];
     58         sta <<= 3;
     59         sta |= code[i];
     60     }
     61     return sta;
     62 }
     63 void AtLast(int *code)
     64 {
     65     for(int i = M; i > 0; i--) code[i] = code[i-1];
     66     code[0] = 0;
     67 }
     68 void slove()
     69 {
     70     mark = 0;
     71     hashmp[mark].init();
     72     hashmp[mark].push(0, 1);       //开始时轮廓线在最上方
     73 
     74     for(int i = 1; i <= N; i++)
     75     {
     76         for(int j = 1; j <= M; j++)
     77         {
     78             hashmp[mark^1].init();//初始化
     79             if(mp[i][j] == 0)     //不能放置
     80             {
     81                 for(int k = 0; k < hashmp[mark].cnt; k++)
     82                 {
     83                     decode(code, hashmp[mark].state[k]);
     84                     code[j-1] = code[j] = 0;
     85                     if(j == M) AtLast(code);
     86                     hashmp[mark^1].push(encode(code),hashmp[mark].sum[k]);
     87                 }
     88             }
     89             else                //可以放置
     90             {
     91                 for(int k = 0; k < hashmp[mark].cnt; k++)
     92                 {
     93                     decode(code, hashmp[mark].state[k]);
     94                     int left, up;
     95                     left = code[j-1]; up = code[j];
     96                     if(left == 0 && up == 0)            //情况1:没有上插头和左插头,新建一个联通分量  
     97                     {
     98                         if(mp[i+1][j] && mp[i][j+1])
     99                         {
    100                             code[j-1] = code[j] = 13;  //如果mp[i][j+1] = 1,则不可能出现j == M的情况
    101                             hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]);
    102                         }
    103                     }
    104                     else if(left && up)                //情况2:有上插头和左插头
    105                     {
    106                         if(left != up)                 //上插头和左插头不联通,合并联通分量。
    107                         {
    108                             code[j-1] = code[j] = 0;   //则不可能再有右插头和下插头
    109                             for(int ii = 0; ii <= M; ii++)
    110                             {
    111                                 if(code[ii] == up) code[ii] = left;
    112                             }
    113                             if(j == M) AtLast(code);
    114                             hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]);
    115                         }
    116                         else if(left == up)            //上插头和左插头联通
    117                         {
    118  
    119                             if(i == ex && j == ey)     //这种情况只可能出现在最后一个可以摆放的位置
    120                             {
    121                                 code[j-1] = code[j] = 0;
    122                                 if(j == M) AtLast(code);
    123                                 hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]);
    124                             }
    125                         }
    126                     }
    127                     else if((left&&(!up)) || (up&&(!left)))//情况3:上插头和左插头只存在一个
    128                     {
    129                         int val;
    130                         if(left) val = left;
    131                         else val = up;
    132                         if(mp[i][j+1])     //右边的格子可走
    133                         {
    134                             code[j] = val; code[j-1] = 0;
    135                             hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]);
    136                         }
    137                         if(mp[i+1][j])    //下面的格子可走
    138                         {
    139                             code[j-1] = val; code[j] = 0;
    140                             if(j == M) AtLast(code);
    141                             hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]);
    142                         }                        
    143                     }
    144                 }
    145             }
    146             mark^=1; 
    147         }
    148     }
    149 }
    150 int main() 
    151 {
    152    // freopen("in.txt", "r", stdin);
    153    //  freopen("out.txt", "w", stdout);
    154     while(~scanf("%d%d", &N, &M))
    155     {
    156         memset(mp, 0, sizeof(mp));
    157         bool flag = false;
    158         for(int i = 1; i <= N; i++)
    159         {
    160             char str[15];
    161             scanf("%s", str);
    162             for(int j = 0; j < M; j++)
    163             {
    164                 if(str[j] == '.')
    165                 {
    166                     mp[i][j+1] = 1;
    167                     ex = i; ey = j+1;
    168                     flag = true;       
    169                 }   
    170                 else if(str[j] == '*') mp[i][j+1] = 0;
    171             }
    172         }
    173         if(flag == false)  //没有空块
    174         {
    175             printf("0
    "); continue;
    176         }
    177         slove();
    178         long long ans = 0;;
    179         for(int i = 0; i < hashmp[mark].cnt; i++)
    180         {
    181             ans += hashmp[mark].sum[i];
    182         }
    183         printf("%lld
    ", ans);
    184     }
    185     return 0;
    186 }
  • 相关阅读:
    WPF程序国际化
    MVVM框架搭建
    最全前端开发面试问题及答案整理
    最小化运行批处理
    C#中App.config文件配置获取
    VS2017 打包成exe
    Inno Setup生成桌面快捷方式
    C#文件读写(txt 简单方式)
    Flume 学习笔记之 Flume NG概述及单节点安装
    快学Scala 第二十课 (trait的构造顺序)
  • 原文地址:https://www.cnblogs.com/titicia/p/4902481.html
Copyright © 2011-2022 走看看