FZU 1977 Pandora adventure (插头dp)
来源:互联网 发布:淘宝运营费用 编辑:程序博客网 时间:2024/05/01 10:29
题意:
给出一个地图,包含三种格子的地图,'O'表示必须走的点,'*'表示可以走的点,'X'表示不能走到的点。问走完必须走的点的回路个数
题解:
这题很明显是单回路问题,但是格子有三种,因此就无法确定左后一个非障碍位置,因为我们引入一个变量标记是否某个状态是否已经形成回路。具体做法:每次将状态解压出来时都要让标记变量赋值为状态的最高位(最高位存的就是否是已经有回路的标记),每次在装以前要判断是否已经有回路,有回路要特殊判断转移方程。
#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 100010#define MAXD 15int N,M;int code[MAXD],maze[MAXD][MAXD];int ch[MAXD];int IsEnd;struct HASHMAP{ int head[HASH],next[STATE],sizes; lld dp[STATE],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; } IsEnd=st&1;//相当于0——m中0的那位数组作为标记是否已经形成环}lld encode(int code[],int m)//最小表示法{ lld st=IsEnd; 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(IsEnd) { ///如果已经形成环路,后面有插头或者必须经过的点说明这个方案是不合法的删去 if(left||up||maze[i][j]==2) continue; code[j-1]=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)///如果在同一个联通分量 { code[j-1]=code[j]=0; IsEnd=1; if(j==M)shift(code,M); hm[cur^1].push(encode(code,M),hm[cur].dp[k]); } else///不再同一个联通分量里面可以进行合并 { 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]); } if(maze[i][j]==1) { code[j]=code[j-1]=0; if(j==M)shift(code,M); 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 c; scanf("%d %d",&N,&M); for(int i=1;i<=N;i++) { getchar(); for(int j=1;j<=M;j++) { scanf("%c",&c); if(c=='*') maze[i][j]=1; else if(c=='O') maze[i][j]=2; } }}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(){ int T; scanf("%d",&T); for(int cas=1;cas<=T;cas++) { init(); printf("Case %d: ",cas); solve(); } return 0;}/**22 2OOO*4 4***OXO****O*XX***/
0 0
- FZU 1977 Pandora adventure(插头DP)
- FZU 1977 Pandora adventure (插头dp)
- FZU 1977 Pandora adventure 插头dp
- FZU - 1977 Pandora adventure【插头DP】
- FZU 1977 Pandora adventure 解题报告(插头DP)
- foj 1977 Pandora adventure(插头DP)
- fzu 1977 Pandora adventure(插头DP一条回路 格子的占用或不占用)
- fzu 1977 Pandora adventure
- fzu 1977 Pandora adventure
- FZU 1977 Pandora adventure
- FZU 1977 Pandora adventure
- fzu1977Pandora adventure【插头dp】
- Pandora adventure FZU1977
- FZU1977 Pandora adventure
- 插头DP
- 插头dp
- 插头dp
- 插头dp
- UVA 11695 Flight Planning 修改一条边使得树的直径最短
- python第四天
- HDU 1671 Phone List(字典树)
- SpringMVC Controller介绍(重点阅读)
- cactus的使用
- FZU 1977 Pandora adventure (插头dp)
- javascript数组的几个常用方法
- 关于初学Java的一些注意要点(一)
- 《第2章:线程安全性》一种常见的加锁约定
- 分享WMRNET-IV低功耗水表、燃气表无线扩频抄表系统 - APPCON
- ExtJs之组件(window)
- 无法打开包含文件#include”cxtypes.h”问题————OpenCV笔记
- 动态链接库的RPATH和RUNPATH解惑
- SUSE Install Oracle