[HDU1693]Eat the Trees

题面在这里

题意

四通格内有部分格子为障碍物,求用数个回路将非障碍物格子全部覆盖的方案数

数据范围

\[1\le n,m\le 11 \]

sol

本人插头DP第一题
入门首推CDQ大佬论文《基于连通性状态压缩的动态规划问题》

插头指两个相邻元素之间是否相连的性质
而插头DP以轮廓线上各个插头的状态
转移时主要按格转移需要相当的时间讨论转移方程,
因此是一种非常难写的状态压缩DP...

这道题轮廓线上只要维护是否联通,也就是0/1两个状态,
最后只要匹配完所有的插头就合法,稍微注意一下障碍物就行。

其实没有学过插头DP的大佬们也是可以做出这种多回路问题的

代码

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define pub push_back
#define puf push_front
#define pob pop_back
#define pof pop_front
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-10;
const int mod=1e8;
const int N=13;
il ll read(){
	RG ll data=0,w=1;RG char ch=getchar();
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
	return data*w;
}

il void file(){
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
}

int T,c,mp[N][N];ll f[N][N][1<<N];
il void solve(){
	RG int n=read(),m=read(),p,q;
	for(RG int i=1;i<=n;i++)
		for(RG int j=1;j<=m;j++)mp[i][j]=read();
	memset(f,0,sizeof(f));f[1][1][0]=1;
	for(RG int i=1;i<=n;i++)
		for(RG int j=1;j<=m;j++){
			p=1<<(j-1);q=1<<j;
			if(j==m){
				if(!mp[i][j])
					for(RG int k=0;k<(1<<(m+1));k++){
						if(!(k&p)&&!(k&q))
							f[i+1][1][k<<1]+=f[i][j][k];
					}
				else 
					for(RG int k=0;k<(1<<(m+1));k++)
						if((k&p)&&!(k&q))
							f[i+1][1][k<<1]+=f[i][j][k];
						else if(!(k&p)&&(k&q))
							f[i+1][1][((k^q)|p)<<1]+=f[i][j][k];
						else if((k&p)&&(k&q))
							f[i+1][1][((k^q)^p)<<1]+=f[i][j][k];
				continue;
			}
			if(!mp[i][j]){
				for(RG int k=0;k<(1<<(m+1));k++)
					if(!(k&p)&&!(k&q))f[i][j+1][k]+=f[i][j][k];
			}
			else {
				for(RG int k=0;k<(1<<(m+1));k++)
					if((k&p)&&(k&q))
						f[i][j+1][(k^p)^q]+=f[i][j][k];
					else if((k&p)&&!(k&q)){
						f[i][j+1][(k^p)|q]+=f[i][j][k];
						f[i][j+1][k]+=f[i][j][k];
					}
					else if(!(k&p)&&(k&q)){
						f[i][j+1][(k|p)^q]+=f[i][j][k];
						f[i][j+1][k]+=f[i][j][k];
					}
				else f[i][j+1][(k|p)|q]+=f[i][j][k];
			}
		}
	printf("Case %d: There are %lld ways to eat the trees.\n",++c,f[n+1][1][0]);
}

int main()
{
	T=read();while(T--)solve();return 0;
}
posted @ 2018-04-02 09:22  cjfdf  阅读(104)  评论(0编辑  收藏  举报