您的位置:首页 > 其它

JOJ 2190: Mondriaan's Dream (状态压缩DP +DFS)

2011-08-23 10:39 507 查看
在网上找了很多解题报告,看了很久才理解,不过理解之后代码还是很好实现的><

还是对每个格2种状态 ,1表示被占 , 0表示不被占 ,

对每一行可以做横放 , 竖放 , 不放, 3种操作, 没种操作都要求出对应上一行的状态, 比如若竖放 , 上一行的状态就必须是0 , 既没被占用,横放和不放对应的上一行必须是1,这样才能将所有的格子都填满,其次对第一行只有横放和不放2种操作, 对状态的转换自己YY下就可以出来,对于状态的转换,是树状的, 所以用DFS更好理解

#include <cstdio>
#include <cstring>

typedef long long ll;
const int maxn=1<<12;

ll dp[13][maxn];
int n,m;

void dfs(int c , int opt)//only horizontal lie and not lie in first row;
{
if(c>=m)
{
if(c==m)dp[0][opt]++;
return;
}
dfs(c+1 , opt<<1);
dfs(c+2 , opt<<2|3);
}

void DFS(int r , int c , int pre , int opt)
//这里的pre并非要对上一行处理,而是根据本行的状态求出上一行对应状态,以便更新DP[][]
{
if(c>=m)
{
if(c==m)dp[r][opt]+=dp[r-1][pre];
return ;
}
DFS(r , c+1 , pre<<1 , opt<<1|1);//vetical
DFS(r , c+2 , pre<<2|3 , opt<<2|3);//horizoncal
DFS(r , c+1 , pre<<1|1 , opt<<1);//
}
void debug ()
{
for (int i=0 ; i<n ; ++i)
{
for (int j=0 ; j<(1<<m) ; ++j)
{
printf("j=%o %d ",j,dp[i][j]);
}
puts("");
}
}
int main ()
{
int cas;
scanf("%d",&cas);
while (cas--)
{
scanf("%d%d",&n,&m);
memset (dp , 0 , sizeof(dp));
if((n&1) && (m&1)){printf("0\n"); continue ;}
if(m>n)n^=m^=n^=m;//行是指数级 , 列式线性的
dfs(0,0);
for (int i=1 ; i<n ; ++i)
DFS(i , 0 , 0 , 0);
ll ans=0;
/*for (int i=0 ; i<(1<<m) ; ++i)
{
ans+=dp[n-1][i];
}*/
//debug ();
//printf("%lld\n",ans);
//本来以为sigma(dp[n-1][i])是答案,debug的时候发现最后一行全部放满的dp[n-1][(1<<m)-1]才是答案
printf("%lld\n",dp[n-1][(1<<m)-1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: