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;
}
相关文章推荐
- hdu 4285 circuits(插头DP多条回路无嵌套环)
- HDU 4285 circuits( 插头dp , k回路 )
- HDU 4285 circuits 解题报告(插头DP)
- HDU 4285 circuits[插头DP]
- HDU 4285 circuits(插头DP)
- hdu 4285 circuits 插头dp
- HDU 1693 Eat the Trees(插头DP,多条回路)
- HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)
- HDOJ 4285 circuits (插头dp 总结)
- hdu 1693(插头DP简单题,多条回路)
- HDU 1964 Pipes(插头DP-回路最小代价)
- HDU 1693 Eat the Trees(插头DP,多条回路)
- hdu 1693 Eat the Trees 插头dp
- 插头dp模板(简单路径+一条回路+广义路径)
- HDU 1964 Pipes (插头DP,变形)
- POJ - 1739 Tony's Tour (单回路插头dp)
- hdu1964之插头DP求最优值
- hdu 1693 Eat the Trees 插头dp
- hdu 4949 Light 插头dp
- hdu 1697 Eat the Trees(插头dp)