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]要慢一些的(主要应该是m小的时候k<tot清空比清空hash表快)。
- #include <cstdio>
- #include <cstring>
- #include <iostream>
- using namespace std;
- #define HASH 100007
- #define STATE 500010
- #define maxd 15
- int maze[maxd][maxd];
- int code[maxd];
- int n,m;
- struct HASHMAP{
- int head[HASH];
- int state[STATE],nxt[STATE];
- int f[STATE];
- int sz;
- void clear(){sz=0;memset(head,-1,sizeof(head));}
- void push(int st,int ans){
- int h=st%HASH;
- for(int i=head[h];i!=-1;i=nxt[i]){
- if(st==state[i]){
- f[i] = f[i]<ans?f[i]:ans;
- return ;
- }
- }
- state[sz]=st,nxt[sz]=head[h],f[sz]=ans;
- head[h]=sz++;
- }
- }hm[2];
- void decode(int st){
- for(int i=m;i>=0;--i) code[i]=st&3,st>>=2;
- }
- int encode(){
- int ret=0;
- for(int i=0;i<=m;++i) ret=ret<<2|code[i];
- return ret;
- }
- void shift(){
- for(int i=m;i;--i) code[i]=code[i-1];
- code[0]=0;
- }
- int ans;
- int zo,oz,oo;
- void dpblank(int i,int j,int cur){
- int mv = j==m?2:0;
- int all = (1<<(2*(m+1)-mv) ) -1;
- for(int k=0;k<hm[cur].sz;++k){
- int st = hm[cur].state[k];
- int left = st&(oo>>(2*(j-1))), up = st&(oo>>(2*j));
- int L = left>>(2*(m-j+1)), U = up>>(2*(m-j));
- int cnt = ((L>>1)+(U>>1))&1;
- if(i==1 || U==2 || maze[i-1][j]==U){
- int st2 = st^left^up;
- if(cnt) st2 = st2 | (zo>>(2*(j-1))) | (zo>>(2*j));
- hm[cur^1].push((st2>>mv)&all, hm[cur].f[k]);
- }
- if(hm[cur].f[k]+2<ans)
- if(i==1 || U==2 || maze[i-1][j]==U){
- int st2 = st^left^up;
- if(!cnt) st2 = st2 | (zo>>(2*(j-1))) | (zo>>(2*j));
- hm[cur^1].push((st2>>mv)&all, hm[cur].f[k]+2);
- }
- if(hm[cur].f[k]+1<ans)
- if(i==1 || U==2 || maze[i-1][j]!=U){
- int st2 = st^left^up;
- if(j>1 && L!=2) st2 = st2 ^ (zo>>(2*(j-2)));
- st2 = st2 | (oz>>(2*(j-1))) | (oz>>(2*j));
- hm[cur^1].push((st2>>mv)&all, hm[cur].f[k]+1);
- }
- }
- }
- void solve(){
- zo = 1<<(2*m);
- oz = 2<<(2*m);
- oo = 3<<(2*m);
- int cur=0;
- hm[0].clear();
- hm[0].push(0,0);
- for(int i=1;i<=n;++i){
- for(int j=1;j<=m;++j){
- hm[cur^1].clear();
- dpblank(i,j,cur);
- cur^=1;
- }
- }
- for(int k=0;k<hm[cur].sz;++k){
- bool yes=true;
- decode(hm[cur].state[k]);
- for(int j=1;j<=m;++j){
- if(code[j]!=2 && code[j]!=maze[n][j]){
- yes=false;
- break;
- }
- }
- if(yes) ans = ans<hm[cur].f[k]?ans:hm[cur].f[k];
- }
- }
- int main(){
- int ca=0;
- while(~scanf("%d%d",&n,&m) && n){
- printf("Case #%d: ",++ca);
- ans=0;
- for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)
- scanf("%1d",maze[i]+j), ans+=maze[i][j];
- ans*=2;
- solve();
- printf("%d\n",ans);
- }
- return 0;
- }
HDU 4949 Light(插头dp、位运算)的更多相关文章
- 基于DP+位运算的RMQ算法
来源:http://blog.csdn.net/y990041769/article/details/38405063 RMQ算法,是一个快速求区间最值的离线算法,预处理时间复杂度O(n*log(n) ...
- [BZOJ1151][CTSC2007]动物园zoo 解题报告|DP|位运算
Description 最近一直在为了学习算法而做题,这道题是初一小神犇让我看的.感觉挺不错于是写了写. 这道题如果是一条线的话我们可以构造一个DP f[i,j]表示以i为起点,i,i+1...i+4 ...
- HDU 5735 Born Slippy(拆值DP+位运算)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5735 [题目大意] 给出一棵树,树上每个节点都有一个权值w,w不超过216,树的根为1,从一个点往 ...
- HDU 5119 Happy Matt Friends(dp+位运算)
题意:给定n个数,从中分别取出0个,1个,2个...n个,并把他们异或起来,求大于m个总的取法. 思路:dp,背包思想,考虑第i个数,取或者不取,dp[i][j]表示在第i个数时,异或值为j的所有取法 ...
- hdu 4336 Card Collector (概率dp+位运算 求期望)
题目链接 Card Collector Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...
- HDU 6186 CS Course (连续位运算)
CS Course Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- HDU 5014 Number Sequence(位运算)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5014 解题报告:西安网赛的题,当时想到一半,只想到从大的开始匹配,做异或运算得到对应的b[i],但是少 ...
- hdu 5491 The Next (位运算)
http://acm.hdu.edu.cn/showproblem.php?pid=5491 题目大意:给定一个数D,它的二进制数中1的个数为L,求比D大的数的最小值x且x的二进制数中1的个数num满 ...
- [poj 1185] 炮兵阵地 状压dp 位运算
Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用&quo ...
随机推荐
- CF459C Pashmak and Buses (构造d位k进制数
C - Pashmak and Buses Codeforces Round #261 (Div. 2) C. Pashmak and Buses time limit per test 1 seco ...
- 简单实用的PHP防注入类实例
这篇文章主要介绍了简单实用的PHP防注入类实例,以两个简单的防注入类为例介绍了PHP防注入的原理与技巧,对网站安全建设来说非常具有实用价值,需要的朋友可以参考下 本文实例讲述了简单实用的PHP防注 ...
- JS抽奖功能代码
HTML <label for="awardListDom">奖项列表</label><br> <input type="tex ...
- SqlServer 还原他服数据库只建立发布却删除不了
本想做测试,从另一台服务器备份数据库还原到本机. 创建了一个发布,却删除不了,提示如下图: 参考论坛:http://bbs.csdn.net/topics/300046417 发现是数据库所有者问题, ...
- [译]git remote
git remote命令让我们可以创建, 查看, 删除一个到其他仓储的连结. 下图展示了我们的本地仓储有两个remote连接, 一个是中央仓储, 一个是其他开发者的仓储. 除了使用完整的url指向他们 ...
- 开机自动连接/断开VPN 批处理
或许大家在工作或生活中有接触到VPN,如果使用Windows自带的VPN来连接,每次开机要像宽带拨号那样,右击该VPN连接图标,然后选择“连接”(如果未记住密码甚至还要输入密码),然后点击确定,有点麻 ...
- PHP简单封装MysqlHelper类
MysqlHelper.class.php 1: <?php 2: 3: /** 4: * Mysql数据帮助类 5: */ 6: class MysqlHelper 7: { 8: func ...
- C和指针 第一章 字符串处理程序
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_COL 20 #def ...
- BZOJ4612——[Wf2016]Forever Young
1.题意:将一个数y转化成b进制数,使得他>=l,且<y,且转化后均为0~9,使b最大. 2.分析:我们发现要么答案的b很小,要么y很小..那我们直接暴力枚举就好了啊 然后判断一下...另 ...
- tableview侧滑删除
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { ) { retu ...