poj 1739 Tony's Tour(插头dp)
2015-01-30 10:21
218 查看
题意:
给出地图,起点是(N,1),终点是(N,M),有障碍物,求有多少种方案能从起点到终点。
题解:
非环形的插头dp,特判一些起点和终点的dp,还要注意一点,从上往下dp的时候因为起点是左下角,所以不存在不建立新插头的方案!不然未走的空格子就被计算成了路径,反而增加累赘的方案数。
给出地图,起点是(N,1),终点是(N,M),有障碍物,求有多少种方案能从起点到终点。
题解:
非环形的插头dp,特判一些起点和终点的dp,还要注意一点,从上往下dp的时候因为起点是左下角,所以不存在不建立新插头的方案!不然未走的空格子就被计算成了路径,反而增加累赘的方案数。
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<map> using namespace std; typedef __int64 lld; #define oo 0x3f3f3f3f #define OO 0x3f3f3f3f3f3f3f3f #define HASH 10007 #define STATE 1000010 #define MAXD 15 int N,M,ex,ey; int code[MAXD]; int maze[MAXD][MAXD]; int ch[MAXD]; int temp_map[MAXD][MAXD]; struct HASHMAP { int head[HASH],next[STATE],sizes; lld dp[STATE]; lld state[STATE]; void init() { sizes=0; memset(head,-1,sizeof head); } void push(lld st,lld ans) { int h=st%HASH; for(int i=head[h];i!=-1;i=next[i]) { if(st==state[i]) { dp[i]+=ans; return ; } } dp[sizes]=ans; state[sizes]=st; next[sizes]=head[h]; head[h]=sizes++; } }hm[2]; void decode(int code[],int m,lld st) { for(int i=m;i>=0;i--) { code[i]=st&7; st>>=3; } } lld encode(int code[],int m)///最小表示法 { lld st=0; int cnt=0; memset(ch,-1,sizeof ch); ch[0]=0; for(int i=0;i<=m;i++) { if(ch[code[i]]==-1) ch[code[i]]=++cnt; code[i]=ch[code[i]]; st<<=3; st|=code[i]; } return st; } void shift(int code[],int m)///换行 移位 { for(int i=m;i>0;i--) code[i]=code[i-1]; code[0]=0; } void dpblank(int i,int j,int cur) { int left,up; for(int k=0;k<hm[cur].sizes;k++) { decode(code,M,hm[cur].state[k]); left=code[j-1]; up=code[j]; ///开头 if((i==N&&j==1)||(i==N&&j==M)) { if((up&&!left)||(!up&&left)) { code[j-1]=code[j]=0; if(j==M)shift(code,M); hm[cur^1].push(encode(code,M),hm[cur].dp[k]); } else if(!up&&!left) { if(maze[i][j+1])//往右走 { code[j-1]=0; code[j]=13; hm[cur^1].push(encode(code,M),hm[cur].dp[k]); } if(maze[i+1][j]) { code[j-1]=13; code[j]=0; if(j==M)shift(code,M); hm[cur^1].push(encode(code,M),hm[cur].dp[k]); } } continue; } if(left&&up)///11 -> 00 有上插头和左插头,这种情况下相当于合并两个连通分量 { if(left!=up)///不存在环才进行dp { code[j-1]=code[j]=0; for(int t=0;t<=M;t++) if(code[t]==up) code[t]=left; if(j==M)shift(code,M); hm[cur^1].push(encode(code,M),hm[cur].dp[k]); } } else if(left||up)///01 || 10 上插头和左插头恰好有一个,这种情况相当于延续原来的连通分量 { int temp; if(left) temp=left; else temp=up; if(maze[i][j+1]) { code[j-1]=0; code[j]=temp; hm[cur^1].push(encode(code,M),hm[cur].dp[k]); } if(maze[i+1][j]) { code[j-1]=temp; code[j]=0; if(j==M)shift(code,M);///切记不可忘记,换行要shift hm[cur^1].push(encode(code,M),hm[cur].dp[k]); } } else///没有上插头和左插头,有下插头和右插头,相当于构成一个新的连通块 { if(maze[i][j+1]&&maze[i+1][j]) { code[j]=code[j-1]=13; hm[cur^1].push(encode(code,M),hm[cur].dp[k]); } ///起点是左下角,不存在不建立新两通快的情况,因为如果不建立新的联通快相当于把上面“未走”的空格给计算成了路径 } } } void dpblock(int i,int j,int cur) { for(int k=0;k<hm[cur].sizes;k++) { decode(code,M,hm[cur].state[k]); code[j-1]=code[j]=0;///因为有障碍物所以 左插头j-1 和 上插头j 都消失了(就是不联通了) if(j==M)shift(code,M); hm[cur^1].push(encode(code,M),hm[cur].dp[k]); } } void init() { memset(maze,0,sizeof maze); char str[MAXD][MAXD]; for(int i=1;i<=N;i++) { getchar(); for(int j=1;j<=M;j++) { scanf("%c",&str[i][j]); if(str[i][j]=='.') maze[i][j]=1; } } } void solve() { int cur=0; lld ans=0; hm[cur].init(); hm[cur].push(0,1); for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) { hm[cur^1].init(); if(maze[i][j]) dpblank(i,j,cur); else dpblock(i,j,cur); cur^=1; } for(int i=0;i<hm[cur].sizes;i++) ans+=hm[cur].dp[i]; printf("%I64d\n",ans); } int main() { while(scanf("%d %d",&N,&M)!=EOF) { if(N==0&&M==0)break; init(); solve(); } return 0; } /** 2 2 .. .. 2 3 #.. ... 3 4 .... .... .... */
相关文章推荐
- poj 1739 Tony's Tour 插头dp模板题
- POJ - 1739 Tony's Tour (单回路插头dp)
- POJ 1739 Tony's Tour (插头DP)
- poj 1739 Tony's Tour 插头dp
- POJ 1739 Tony's Tour 插头DP
- POJ 1739 Tony's Tour 解题报告(插头DP)
- poj 1739 Tony's Tour 插头dp
- POJ 1739 Tony's Tour(插头DP)
- POJ 1739 Tony's Tour, 连通性状态压缩DP
- POJ 1739 Tony's Tour(插头DP)
- poj2411 Mondriaan's Dream 插头dp做法
- POJ 1739 Tony's Tour (插头DP,轮廓线DP)
- POJ-1739 Tony's Tour 插头DP(单条路径)
- HDOJ 1400 & POJ 2411 - Mondriaan's Dream 状态压缩DP
- POJ-2411 Mondriaan's Dream 状态压缩DP
- POJ2704 Pascal's Travels (记忆化DP)
- poj 1739 Tony's Tour 插头dp
- poj 2411 && zoj 1100 Mondriaan's Dream ———状态压缩dp
- poj 2411 Mondriaan's Dream_状态压缩dp
- poj 2411 Mondriaan's Dream 状态压缩DP