您的位置:首页 > 产品设计 > UI/UE

HDU 4285 circuits(回路不能嵌套的插头DP)

2017-08-07 13:41 323 查看


circuits

Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1149    Accepted Submission(s): 393


Problem Description

  Given a map of N * M (2 <= N, M <= 12) , '.' means empty, '*' means walls. You need to build K circuits and no circuits could be nested in another. A circuit is a route connecting adjacent cells in a cell sequence, and also connect the first cell and the
last cell. Each cell should be exactly in one circuit. How many ways do we have?

 

Input

  The first line of input has an integer T, number of cases.

  For each case:

  The first line has three integers N M K, as described above.

  Then the following N lines each has M characters, ‘.’ or ‘*’.

 

Output

  For each case output one lines.

  Each line is the answer % 1000000007 to the case.

 

Sample Input

2
4 4 1
**..
....
....
....
4 4 1
....
....
....
....

 

Sample Output

2
6

 

Source

2012 ACM/ICPC Asia Regional Tianjin Online 

 

Recommend

liuyiding

题目大意:

    有一个n*m的矩阵,在矩阵上找K条不相交不嵌套的回路,使得每个点被经过恰好一次,求方案数。

解题思路:

    首先在矩阵上找回路,使得每个点被经过一次,显然是一个插头dp,至于题目要求的刚好K条回路,只需要在状态中加一维当前已经包含的回路数即可。为了使回路之间不嵌套需要在没次形成回路的时候判定一下轮廓线左边右边的插头是否为偶数,如果为偶数则可以合并,否则存在嵌套不能合并(画一下图就可以理解)。

AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <string>
#include <map>
#include <set>
#include <list>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define fi first
#define se second
#define mem(a,b) memset((a),(b),sizeof(a))

const int MAXN=12+3;
const int MOD=1000000007;

struct HashMap
{
const static int mod=300007;
const static int maxn=1000010;
int head[mod];//链表头指针
int next[maxn];//指向链表下一个节点
int size;//当前节点数
LL key[maxn];
int val[maxn];//键,值
void clear()
{
size=0;
memset(head,-1,sizeof head);
}
inline void insert(LL _key,int _val)
{
int p=_key%mod;//取模后对应的链
for(int i=head[p];~i;i=next[i])
if(key[i]==_key)
{
val[i]=(val[i]+_val)%MOD;
return ;
}
key[size]=_key;
val[size]=_val;
next[size]=head[p];
head[p]=size++;
}
}hm[2];

int maze[MAXN][MAXN];
int tmp_state[MAXN];
int ch[MAXN];
int num;//圈的个数
int N, M, K;

void decode(int *tmp_state, int m, LL key)
{
num=key&63;//前6位表示当前状态的环数
key>>=6;
for(int i=m;i>=0;--i)
{
tmp_state[i]=key&7;
key>>=3;
}
}

LL encode(int *tmp_state, int m)//最小表示法
{
int cnt=1;
mem(ch, -1);
ch[0]=0;
LL key=0;
for(int i=0;i<=m;++i)
{
if(ch[tmp_state[i]]==-1)
ch[tmp_state[i]]=cnt++;
tmp_state[i]=ch[tmp_state[i]];
key<<=3;
key|=tmp_state[i];
}
key<<=6;
key|=num;
return key;
}

void dp_blank(int y, int x, bool now)//对可以进入的地区dp
{
for(int i=0;i<hm[now].size;++i)
{
decode(tmp_state, M, hm[now].key[i]);
int left=tmp_state[x-1], up=tmp_state[x];
if(left && up)
{
if(left==up)
{
if(num>=K)
continue;
int t=0;//为了避免环嵌套的情况,两边的插头数必须为偶数
for(int p=0;p<x-1;++p)
if(tmp_state[p])
++t;
if(t&1)
continue;
++num;
tmp_state[x-1]=tmp_state[x]=0;
hm[!now].insert(encode(tmp_state, M-(x==M)), hm[now].val[i]);
}
else
{
tmp_state[x-1]=tmp_state[x]=0;
for(int i=0;i<=M;++i)
if(tmp_state[i]==up)
tmp_state[i]=left;
hm[!now].insert(encode(tmp_state, M-(x==M)), hm[now].val[i]);
}
}
else if(left || up)
{
int t=left?left:up;
if(maze[y][x+1])
{
tmp_state[x-1]=0;
tmp_state[x]=t;
hm[!now].insert(encode(tmp_state, M), hm[now].val[i]);
}
if(maze[y+1][x])
{
tmp_state[x-1]=t;
tmp_state[x]=0;
hm[!now].insert(encode(tmp_state, M-(x==M)), hm[now].val[i]);
}
}
else
{
if(maze[y][x+1] && maze[y+1][x])
{
tmp_state[x-1]=tmp_state[x]=13;
hm[!now].insert(encode(tmp_state, M-(x==M)), hm[now].val[i]);
}
}
}
}

void dp_wall(int y, int x, bool now)//对不可进入的地区dp
{
for(int i=0;i<hm[now].size;++i)
{
decode(tmp_state, M, hm[now].key[i]);
hm[!now].insert(encode(tmp_state, M-(x==M)), hm[now].val[i]);
}
}

void solve()
{
bool now=0;
hm[now].clear();
hm[now].insert(0, 1);
for(int i=1;i<=N;++i)
for(int j=1;j<=M;++j)
{
hm[!now].clear();
if(maze[i][j])
dp_blank(i, j, now);
else dp_wall(i, j, now);
now^=1;
}
int ans=0;
for(int i=0;i<hm[now].size;++i)
if(hm[now].key[i]==K)
ans=(ans+hm[now].val[i])%MOD;
printf("%d\n", ans);
}

int main()
{
int T_T;
scanf("%d", &T_T);
while(T_T--)
{
scanf("%d%d%d", &N, &M, &K);
mem(maze, 0);
for(int i=1;i<=N;++i)
{
char s[MAXN];
scanf("%s", s);
for(int j=1;j<=M;++j)
if(s[j-1]=='.')
maze[i][j]=1;
}
solve();
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: