轮廓线DP(插头DP 裸 经典骨牌)
来源:互联网 发布:linux解压zip 编辑:程序博客网 时间:2024/06/02 10:06
引言:所谓轮廓线,不是某一行,或者某一列,而是指某一个特定轮廓的状态。
放置骨牌的约定:(保证放置有最优子结构)
假设我们正在放置第i行的骨牌,那么会有下面3种方式:
灰色表示已经有的骨牌,绿色表示新放置的骨牌。
每一种放置方法解释如下,假设当第i行的状态为x,第i-1行的状态为y:
简单的例子:
Tiling a Grid With Dominoes
http://acm.hdu.edu.cn/showproblem.php?pid=1992
限制了棋盘宽度为4,数据不超过int,只有长度22以内满足答案。
手写状态找规律。
http://www.cnblogs.com/lzsz1212/archive/2012/05/02/2478839.html
把这个变成更一般的问题,如果不限制棋盘的宽,
hihocoder 骨牌问题讨论了窄棋盘情况下(2^min(n,m) 小于200),构造转移矩阵,快速幂的求法。
http://hihocoder.com/contest/hiho43/problem/1
转移矩阵构造法,y为i-1行状态,x为i行状态,dfs构造是K^2的复杂度,K=min(n,m)。
void dfs(int x,int y,int col){ if(col==K){ d[y][x]=1; return; } dfs(x<<1,(y<<1)|1,col+1); dfs((x<<1)|1,y<<1,col+1); if(col+2<=K){ dfs((x<<2)|3, (y<<2)|3, col+2); }}
那么复杂度就是k^3*logn,当k<=7时(2^7 = 128)的计算效率是可以接受的。
#include <cstdio>#include <iostream>using namespace std;typedef long long LL;const int maxn = 1<<7;const int mod = 12357;int d[maxn][maxn];int K,ALL;void dfs(int x,int y,int col){ if(col==K){ d[y][x]=1; return; } dfs(x<<1,(y<<1)|1,col+1); dfs((x<<1)|1,y<<1,col+1); if(col+2<=K){ dfs((x<<2)|3, (y<<2)|3, col+2); }}void mul(int a[][maxn],int b[][maxn],int c[][maxn]){ for(int i=0;i<ALL;i++){ for(int j=0;j<ALL;j++){ c[i][j]=0; } } LL t; for(int i=0;i<ALL;i++){ for(int j=0;j<ALL;j++){ if(!a[i][j])continue; for(int k=0;k<ALL;k++){ if(b[j][k]){ t=(LL)a[i][j]*b[j][k]; t+=c[i][k]; c[i][k]=t%mod; } } } }}void cpy(int a[][maxn],int b[][maxn]){ for(int i=0;i<ALL;i++){ for(int j=0;j<ALL;j++){ a[i][j]=b[i][j]; } }}void E(int a[][maxn]){ for(int i=0;i<ALL;i++){ a[i][i]=1; for(int j=i+1;j<ALL;j++){ a[i][j]=a[j][i]=0; } }}int e[maxn][maxn],tmp[maxn][maxn];int main(){// freopen("data.in","r",stdin); int n; scanf("%d%d",&K,&n); dfs(0,0,0); ALL=1<<K; E(e); while(n>0){ if(n&1) { mul(e,d,tmp); cpy(e,tmp); } mul(d,d,tmp); cpy(d,tmp); n>>=1; } printf("%d\n",e[ALL-1][ALL-1]); return 0;}
uva11270同此题 ,大白书精讲,但是n*m<101,棋盘可能不是窄棋盘,k^3*logn矩阵运算会超时。
考虑到n<=10,可以构造2^n*n个转移方程,m轮递求解。
bfs可以避免访问不能求解的状态。状态st=k4k3k2k1k0,ki表示一个二进制位,有方块就为1,否则为0。
#include <cstdio>#include <iostream>#include <cstring>using namespace std;typedef long long LL;typedef LL type;typedef pair<int,LL> pil;#define mp make_pair#define FF first#define SS secondconst int maxn = 1<<10;int p[2][maxn];pil q[2][maxn];int tail[2];void init(int cur){ memset(p[cur],-1,sizeof p[cur]); tail[cur]=0;}int main(){ int n,m,cur,st,pos,nst,hi; LL cnt; while(scanf("%d%d",&m,&n)!=EOF){ if(m>n) swap(m,n); cur=0; st = (1<<m)-1; hi = 1<<(m-1); init(cur); p[0][st]=tail[cur]; pos = tail[cur]++; cnt = 1; q[cur][pos]=mp(st,cnt); for(int i=0;i<n;i++){ for(int j=0;j<m;j++,cur^=1){ init(cur^1); for(int k=tail[cur]-1;k>=0;k--){ st = q[cur][k].FF; cnt = q[cur][k].SS; if(st & hi){ nst = (st^hi)<<1; if((pos=p[cur^1][nst])==-1){ pos = tail[cur^1]++; p[cur^1][nst] = pos; q[cur^1][pos]=mp(nst,cnt); }else{ q[cur^1][pos].SS += cnt; } if(j && !(st&1)){ nst = ((st^hi)<<1)|3; if((pos=p[cur^1][nst])==-1){ pos = tail[cur^1]++; p[cur^1][nst] = pos; q[cur^1][pos]=mp(nst,cnt); }else{ q[cur^1][pos].SS += cnt; } } }else{ nst = (st<<1)|1; if((pos=p[cur^1][nst])==-1){ pos = tail[cur^1]++; p[cur^1][nst] = pos; q[cur^1][pos]=mp(nst,cnt); }else{ q[cur^1][pos].SS += cnt; } } } } } st = (1<<m)-1; pos = p[cur][st]; cnt = q[cur][pos].SS; printf("%lld\n",cnt); } return 0;}
对于更复杂的插头DP问题后面再讨论
1 0
- 轮廓线DP(插头DP 裸 经典骨牌)
- 骨牌覆盖(轮廓线DP)
- POJ 2411 Mondriaan's Dream(插头DP,轮廓线)
- hdu4804 Campus Design 插头|轮廓线DP
- HDU 1992 Tiling a Grid With Dominoes(轮廓线dp || 插头dp 简讲)
- POJ-2411-Mondriaan's Dream-轮廓线dp(插头dp)
- hdu 1693 Eat the Trees 轮廓线 插头dp
- ural 1519 Formula 1(轮廓线|插头DP|括号配对)
- UVA11270 Tiling Dominoes 轮廓线|插头 DP入门
- 棋盘覆盖2(1X2骨牌 和 L型骨牌 混合铺满)(强行轮廓线DP)
- poj3133之经典插头DP
- 插头dp-基于连通性,维护轮廓线的状压dp
- UVA 11270 Tiling Dominoes(轮廓线DP经典)
- BZOJ3125city (插头DP)
- 插头DP
- 插头dp
- 插头dp
- 插头dp
- tomcat 安装版下载
- Sencha Touch 修改默认主题
- C++之观察者模式(订阅-发布模式)
- 虚拟机安装debian失败:安装系统
- 100多道经典的JAVA面试题及答案解析
- 轮廓线DP(插头DP 裸 经典骨牌)
- SQLServer的Lead和Lag实现
- C#调用DOS开启WIFI
- VMware安装64位操作系统失败
- iOS UITextView限制字数
- Python IDE:PyCharm中的那些实用功能
- #300 (div.1 2) C. Tourist's Notes
- Handler 消息传递机制
- python的类中变量、函数的特殊命名--意义