首页 > 代码库 > HDU 4949 Light(插头dp、位运算)
HDU 4949 Light(插头dp、位运算)
比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题。。。。
因为写完之后,无限TLE。。。
直到后来用位运算代替了我插头dp常用的decode、encode、shift三个函数以及改改HASH值才勉强过的。。。7703ms
题意:给一个N*M的01矩阵,每次可以选一个格子进行2种操作,①翻转邻居格子②翻转邻居格子和自己。输出最小的总操作数使得矩阵全为0.
显然每个格子有4种操作(一、不操作;二、①②;三、①;四、②)。
一开始写的时候用2位表示一个插头,一位用于表示翻转当前格子,一位表示插头的源头需要被翻转。然后就是2*3*(4^10)感觉有点不科学。
后来发现,其实,我们可以这样归类,①不操作(花费0);②翻自己(花费2);③翻转邻居(花费1);这样就是2*3*(3^10)
其中③包括2种情况,事实上,如果对一个格子A进行了第③种操作,那这个格子的邻居格子BCDE做任何操作,A都可以熄灯。
还有就是,答案一定小于等于一开始矩阵的1的个数的2倍,可以用这个进行一定程度的剪枝。
然后就是各种位运算了。。。。搞得我都晕了。。。
另外,其实,因为这样插头dp需要消耗很多额外的花费(清空hash表什么的),所以速度应该是比直接dp[i][j][k]要慢一些的(吧?)。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 using namespace std; 5 6 7 #define HASH 100007 8 #define STATE 500010 9 #define maxd 15 10 11 int maze[maxd][maxd]; 12 int code[maxd]; 13 int n,m; 14 struct HASHMAP{ 15 int head[HASH]; 16 int state[STATE],nxt[STATE]; 17 int f[STATE]; 18 int sz; 19 void clear(){sz=0;memset(head,-1,sizeof(head));} 20 void push(int st,int ans){ 21 int h=st%HASH; 22 for(int i=head[h];i!=-1;i=nxt[i]){ 23 if(st==state[i]){ 24 f[i] = f[i]<ans?f[i]:ans; 25 return ; 26 } 27 } 28 state[sz]=st,nxt[sz]=head[h],f[sz]=ans; 29 head[h]=sz++; 30 } 31 }hm[2]; 32 void decode(int st){ 33 for(int i=m;i>=0;--i) code[i]=st&3,st>>=2; 34 } 35 int encode(){ 36 int ret=0; 37 for(int i=0;i<=m;++i) ret=ret<<2|code[i]; 38 return ret; 39 } 40 void shift(){ 41 for(int i=m;i;--i) code[i]=code[i-1]; 42 code[0]=0; 43 } 44 int ans; 45 int zo,oz,oo; 46 void dpblank(int i,int j,int cur){ 47 int mv = j==m?2:0; 48 int all = (1<<(2*(m+1)-mv) ) -1; 49 for(int k=0;k<hm[cur].sz;++k){ 50 int st = hm[cur].state[k]; 51 int left = st&(oo>>(2*(j-1))), up = st&(oo>>(2*j)); 52 int L = left>>(2*(m-j+1)), U = up>>(2*(m-j)); 53 int cnt = ((L>>1)+(U>>1))&1; 54 if(i==1 || U==2 || maze[i-1][j]==U){ 55 int st2 = st^left^up; 56 if(cnt) st2 = st2 | (zo>>(2*(j-1))) | (zo>>(2*j)); 57 hm[cur^1].push((st2>>mv)&all, hm[cur].f[k]); 58 } 59 if(hm[cur].f[k]+2<ans) 60 if(i==1 || U==2 || maze[i-1][j]==U){ 61 int st2 = st^left^up; 62 if(!cnt) st2 = st2 | (zo>>(2*(j-1))) | (zo>>(2*j)); 63 hm[cur^1].push((st2>>mv)&all, hm[cur].f[k]+2); 64 } 65 if(hm[cur].f[k]+1<ans) 66 if(i==1 || U==2 || maze[i-1][j]!=U){ 67 int st2 = st^left^up; 68 if(j>1 && L!=2) st2 = st2 ^ (zo>>(2*(j-2))); 69 st2 = st2 | (oz>>(2*(j-1))) | (oz>>(2*j)); 70 hm[cur^1].push((st2>>mv)&all, hm[cur].f[k]+1); 71 } 72 } 73 } 74 void solve(){ 75 zo = 1<<(2*m); 76 oz = 2<<(2*m); 77 oo = 3<<(2*m); 78 int cur=0; 79 hm[0].clear(); 80 hm[0].push(0,0); 81 for(int i=1;i<=n;++i){ 82 for(int j=1;j<=m;++j){ 83 hm[cur^1].clear(); 84 dpblank(i,j,cur); 85 cur^=1; 86 } 87 } 88 for(int k=0;k<hm[cur].sz;++k){ 89 bool yes=true; 90 decode(hm[cur].state[k]); 91 for(int j=1;j<=m;++j){ 92 if(code[j]!=2 && code[j]!=maze[n][j]){ 93 yes=false; 94 break; 95 } 96 } 97 if(yes) ans = ans<hm[cur].f[k]?ans:hm[cur].f[k]; 98 } 99 }100 int main(){101 int ca=0;102 while(~scanf("%d%d",&n,&m) && n){103 printf("Case #%d: ",++ca);104 ans=0;105 for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) scanf("%1d",maze[i]+j), ans+=maze[i][j];106 ans*=2;107 solve();108 printf("%d\n",ans);109 }110 return 0;111 }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。