URAL 1519 Formula 1 (插头DP,常规)

题意:给一个n*m的矩阵,格子中是‘*‘则是障碍格子,不允许进入,其他格子都是必走的格子,所走格子形成一条哈密顿回路,问有多少种走法?

思路:

  本来是很基础的题,顿时不知道进入了哪个坑。这篇插头DP的文章够详细,推荐一看(最好不要照抄代码)。

  细节要小心,比如输出用I64d,必须用long long,判断是否无哈密顿回路,位操作等等。

  这次仍然用括号表示法,1表示(,2表示)。

  1 #include <bits/stdc++.h>
  2 #define pii pair<int,int>
  3 #define INF 0x3f3f3f3f
  4 #define LL long long
  5 using namespace std;
  6 const int N=20;
  7 const int mod=12357;
  8 const int NN=1000010;
  9 char g[N][N];
 10 int cur, n, m, ex, ey;
 11 struct Hash_Map
 12 {
 13     int head[mod];      //桶指针
 14     int next[NN];        //记录链的信息
 15     int status[NN];      //状态
 16     LL  value[NN];       //状态对应的DP值。
 17     int size;
 18
 19     void clear()    //清除哈希表中的状态
 20     {
 21         memset(head, -1, sizeof(head));
 22         size = 0;
 23     }
 24
 25     void insert(int st, LL val)  //插入状态st的值为val
 26     {
 27         int h = st%mod;
 28         for(int i=head[h]; i!=-1; i=next[i])
 29             if(status[i] == st) //这个状态已经存在,累加进去。
 30             {
 31                 value[i] += val;
 32                 return ;
 33             }
 34         status[size]= st;           //找不到状态st,则插入st。
 35         value[size] = val;
 36         next[size] = head[h] ;      //新插入的元素在队头
 37         head[h] = size++;
 38     }
 39 }hashmap[2];
 40
 41 int getbit(int s,int pos)   //取出状态s的第pos个插头
 42 {
 43     int bit=0;
 44     if(s&(1<<(2*pos+1)))  bit+=2;    //高位对应高位
 45     if(s&(1<<2*pos))    bit+=1;
 46     return bit;
 47 }
 48 int setbit(int s,int pos,int bit)   //将状态s的第pos个插头设置为bit
 49 {
 50     if(s&(1<<2*pos ))     s^=1<<(2*pos);
 51     if(s&(1<<(2*pos+1)))  s^=1<<(2*pos+1);
 52     return (s|(bit<<2*pos));
 53 }
 54
 55 int Fr(int s,int pos,int bit)   //寻找状态s的第pos个插头对应的右括号。
 56 {
 57     int cnt=0;
 58     for(pos+=2; pos<m; pos++)
 59     {
 60         if(getbit(s, pos)==3-bit)   cnt++;
 61         if(getbit(s, pos)==bit)     cnt--;
 62         if(cnt==-1)         return setbit(s, pos, 3-bit);
 63     }
 64 }
 65 int Fl(int s,int pos,int bit)   //寻找状态s的第pos个插头对应的左括号。
 66 {
 67     int cnt=0;
 68     for(pos--; pos>=0; pos--)
 69     {
 70         if(getbit(s, pos)==3-bit)  cnt++;
 71         if(getbit(s, pos)==bit)    cnt--;
 72         if( cnt==-1)    return setbit(s, pos, 3-bit);
 73     }
 74 }
 75
 76 void DP(int i,int j)    //非障碍空格
 77 {
 78     for(int k=0,t; k<hashmap[cur^1].size; k++)
 79     {
 80         int s=hashmap[cur^1].status[k];
 81         LL v=hashmap[cur^1].value[k];
 82         int R=getbit(s,j), D=getbit(s,j+1);
 83         if(g[i][j]==‘*‘)    //障碍格子
 84         {
 85             if( R==0 && D==0 )    hashmap[cur].insert(s, v);
 86             continue ;
 87         }
 88         if(R && D)  //两个括号
 89         {
 90             t=(setbit(s,j,0)&setbit(s,j+1,0));
 91             if(R==D)    //同个方向的括号
 92             {
 93                 if(R==1)    t=Fr(t, j, 2);  //要改
 94                 else        t=Fl(t, j, 1);
 95                 hashmap[cur].insert(t, v);
 96             }
 97             if( R==2 && D==1 )        //不同的连通分量
 98                 hashmap[cur].insert(t, v);
 99             if(i==ex && j==ey && R==1 && D==2 )  //终点时‘(‘和‘)‘才可以合并。
100                 hashmap[cur].insert(t, v);
101         }
102         else if(R || D)     //仅1个括号
103         {
104             hashmap[cur].insert(s,v);
105             if(R)   t=setbit(setbit(s,j,0),j+1,R);
106             else    t=setbit(setbit(s,j+1,0),j,D);
107             hashmap[cur].insert(t,v);
108         }
109         else                //无括号
110             hashmap[cur].insert( setbit(s,j,1)|setbit(s,j+1,2), v);
111     }
112 }
113
114 void cal()
115 {
116     if(ex==-1)  return ;  //无空格
117     for(int i=0; i<n; i++)
118     {
119         cur^=1;
120         hashmap[cur].clear();
121         for(int j=0; j<hashmap[cur^1].size; j++)    //新行,需要左移一下状态。
122             if( getbit( hashmap[cur^1].status[j], m)==0 )   //多余的状态需要去除
123                 hashmap[cur].insert( hashmap[cur^1].status[j]<<2, hashmap[cur^1].value[j] );
124         for(int j=0; j<m; j++)
125         {
126             cur^=1;
127             hashmap[cur].clear();
128             DP(i,j);
129             if(i==ex && j==ey)    return ;  //终点
130         }
131     }
132 }
133
134 LL print()
135 {
136     for(int i=0; i<hashmap[cur].size; i++)  //寻找轮廓线状态为0的值。
137         if(  hashmap[cur].status[i]==0 )
138             return hashmap[cur].value[i];
139     return 0;
140 }
141 int main()
142 {
143     //freopen("input.txt", "r", stdin);
144     while(~scanf("%d%d",&n,&m))
145     {
146         ex=ey=-1;
147         cur=0;
148         for(int i=0; i<n; i++)      //输入矩阵
149             for(int j=0; j<m; j++)
150             {
151                 char c=getchar();
152                 if(c==‘.‘||c==‘*‘)
153                 {
154                     g[i][j]=c;
155                     if( c==‘.‘ )    ex=i,ey=j;//终点空格
156                 }
157                 else    j--;
158             }
159
160         hashmap[cur].clear();
161         hashmap[cur].insert(0, 1);  //初始状态
162         cal();
163         cout<<print()<<endl;
164     }
165     return 0;
166 }

AC代码

时间: 2024-11-08 14:16:00

URAL 1519 Formula 1 (插头DP,常规)的相关文章

【bzoj1814】Ural 1519 Formula 1 插头dp

题目描述 一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数. 输入 The first line contains the integer numbers N and M (2 ≤ N, M ≤ 12). Each of the next N lines contains M characters, which are the corresponding cells of the rectangle. Character "." (full stop)

bzoj 1814: Ural 1519 Formula 1 插头dp经典题

用的括号序列,听说比较快. 然并不会预处理,只会每回暴力找匹配的括号. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define N 199917 6 #define ll long long 7 #define bp 1<<bit[j-1] 8 #define bq 1<<bit[j] 9 using nam

【URAL 1519】【插头dp模板】Formula 1

1519. Formula 1 Time limit: 1.0 second Memory limit: 64 MB Background Regardless of the fact, that Vologda could not get rights to hold the Winter Olympic games of 20**, it is well-known, that the city will conduct one of the Formula 1 events. Surely

[URAL 1519] Formula 1 轮廓线DP 括号序列

题意 n * m 的矩形, 有坏点, 问哈密顿回路数量. n, m <= 11 . 分析 1. 确立状态 我们考虑轮廓线DP. 为此, 我们要刻画并量化轮廓线的相关信息: ① 插头是否存在? ② 插头的连通性. 我们发现: 插头一一对应, 且互不相交. 于是考虑使用括号序列刻画轮廓线. 至于量化, 我们将一个括号序列当做一个三进制数即可. 2. 转移 从上一行的最后一个, 转移到当前行的第一个: 位移. 当前格子为坏点: 对于没有插头插到当前点的状态原样复制. 否则: (1) L = # , R

bzoj1814: Ural 1519 Formula 1 2011-12-20

1814: Ural 1519 Formula 1Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 263  Solved: 70[Submit][Status][Discuss]DescriptionRegardless of the fact, that Vologda could not get rights to hold the Winter Olympic games of 20**, it is well- known, that the 

URAL - 1519 Formula 1 (插头DP)

这里写链接内容 刚开始学插头dp好吃力,看了别人的代码有点看不懂,所以就参考了别人的代码,写了注释,希望有帮助 如果看不懂可以问 //下面所说的情况全在论文中的第13页 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 13 #define S1 14000 #define S2 1600000 struct Queue{ int opt; long

Ural1519 Formula 1(插头dp)

原题网址:http://acm.timus.ru/problem.aspx?space=1&num=1519 有关插头dp和状态压缩请参考:http://wenku.baidu.com/link?url=AFuYe_EfR5yXMNK0rY-TaLe6LLgKhsOVxBM1RQULxElPrvjQVlO724nUxlXtaDx4aLp7FHIz8AexYiTy06_r4CV5XUs6c9lM5vpz5kDr6HG 详细代码(c++): 1 #include <cstdio> 2 #i

[URAL1519] Formula 1 [插头dp入门]

题面: 传送门 思路: 先理解一下题意:实际上就是要你求这个棋盘中的哈密顿回路个数,障碍不能走 看到这个数据范围,还有回路处理,就想到使用插头dp来做了 观察一下发现,这道题因为都是回路,所以联通块上方的插头一定两两配对,可以使用括号序列代替最小表示法 分情况讨论一下 情况一:当前格子上方和左方都没有插头 这种时候可以继续,也可以给当前格子加一个下插头一个右插头,相当于一个新的联通分量 情况二:上方有一个下插头,左边没有 这时有两个决策:可以向右转,也可以继续向下,操作就是分别给这个格子一个右插

【插头DP】URAL 1519 Formula 1

通道:http://acm.timus.ru/problem.aspx?space=1&num=1519 题意:单回路,经过全部可达点,有阻碍点. 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAX_N = 13; const int MAX_M = 13; const int HASH = 10007; const in