卧薪尝胆,厚积薄发。
Formula 1
Date: Wed May 30 20:25:19 CST 2018 In Category: NoCategory

Description:

$N\times M$ 的网格中有一些点不能走,求汉密顿回路条数。
$2\le N,M\le 12$

Solution:

插头 $DP$ 入门题,连通性用最小表示法表示。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
int n,m;
#define MAXD 15
#define HASH 30007
#define STATE 1000010
bool map[MAXD][MAXD];
int ch[MAXD];
int code[MAXD];
int lasti,lastj;
bool getc()
{
char c = getchar();
while(c != '*' && c != '.')c = getchar();
return (c == '.');
}
struct Hash
{
int head[HASH],next[STATE],siz;
ll data[STATE],f[STATE];
void init()
{
siz = 0;
memset(head,0,sizeof(head));
return;
}
void add(ll st,ll ans)
{
int hash = st % HASH;
for(int i = head[hash];i != 0;i = next[i])if(data[i] == st){f[i] += ans;return;}
++siz;data[siz] = st;f[siz] = ans;next[siz] = head[hash];head[hash] = siz;
return;
}
}h[2];
void decode(int *code,int m,ll st)
{
for(int i = m;i >= 0;--i)
{
code[i] = st & 7;
st = st >> 3;
}
return;
}
ll encode(int *code,int m)
{
ll res = 0;
int cnt = 0;
memset(ch,-1,sizeof(ch));
ch[0] = 0;
for(int i = 0;i <= m;++i)
{
if(ch[code[i]] == -1)ch[code[i]] = ++cnt;
code[i] = ch[code[i]];
res = res << 3;
res |= code[i];
}
return res;
}
void shift(int *code,int m)
{
for(int i = m;i > 0;--i)code[i] = code[i - 1];
code[0] = 0;
return;
}
void dpblank(int i,int j,int cur)
{
int left,up;
for(int k = 1;k <= h[cur].siz;++k)
{
decode(code,m,h[cur].data[k]);
left = code[j - 1];up = code[j];
if(left && up)
{
if(left == up)
{
if(i == lasti && j == lastj)
{
code[j - 1] = code[j] = 0;
if(j == m)shift(code,m);
h[cur ^ 1].add(encode(code,m),h[cur].f[k]);
}
}
else
{
code[j - 1] = code[j] = 0;
for(int t = 0;t <= m;++t)if(code[t] == up)code[t] = left;
if(j == m)shift(code,m);
h[cur ^ 1].add(encode(code,m),h[cur].f[k]);
}
}
else if((left && (up == 0)) || ((left == 0) && up))
{
int t;
if(left)t = left;
else t = up;
if(map[i][j + 1])
{
code[j - 1] = 0;
code[j] = t;
h[cur ^ 1].add(encode(code,m),h[cur].f[k]);
}
if(map[i + 1][j])
{
code[j - 1] = t;
code[j] = 0;
if(j == m)shift(code,m);
h[cur ^ 1].add(encode(code,m),h[cur].f[k]);
}
}
else
{
if(map[i][j + 1] && map[i + 1][j])
{
code[j - 1] = code[j] = 13;
h[cur ^ 1].add(encode(code,m),h[cur].f[k]);
}
}
}
return;
}
void dpblock(int i,int j,int cur)
{
for(int k = 1;k <= h[cur].siz;++k)
{
decode(code,m,h[cur].data[k]);
code[j - 1] = code[j] = 0;
if(j == m)shift(code,m);
h[cur ^ 1].add(encode(code,m),h[cur].f[k]);
}
return;
}
void solve()
{
int cur = 0;
h[cur].init();
h[cur].add(0,1);
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= m;++j)
{
h[cur ^ 1].init();
if(map[i][j])dpblank(i,j,cur);
else dpblock(i,j,cur);
cur ^= 1;
}
}
ll ans = 0;
for(int i = 1;i <= h[cur].siz;++i)
{
ans += h[cur].f[i];
}
cout << ans << endl;
return;
}
int main()
{
memset(map,false,sizeof(map));
lasti = lastj = 0;
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= m;++j)
{
if(map[i][j] = getc())
{
lasti = i;lastj = j;
}
}
}
if(lasti == 0)
{
puts("0");
return 0;
}
solve();
return 0;
}
In tag: DP-插头DP
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡