比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题。。

因为写完之后,无限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、位运算)的更多相关文章

  1. 基于DP+位运算的RMQ算法

    来源:http://blog.csdn.net/y990041769/article/details/38405063 RMQ算法,是一个快速求区间最值的离线算法,预处理时间复杂度O(n*log(n) ...

  2. [BZOJ1151][CTSC2007]动物园zoo 解题报告|DP|位运算

    Description 最近一直在为了学习算法而做题,这道题是初一小神犇让我看的.感觉挺不错于是写了写. 这道题如果是一条线的话我们可以构造一个DP f[i,j]表示以i为起点,i,i+1...i+4 ...

  3. HDU 5735 Born Slippy(拆值DP+位运算)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5735 [题目大意] 给出一棵树,树上每个节点都有一个权值w,w不超过216,树的根为1,从一个点往 ...

  4. HDU 5119 Happy Matt Friends(dp+位运算)

    题意:给定n个数,从中分别取出0个,1个,2个...n个,并把他们异或起来,求大于m个总的取法. 思路:dp,背包思想,考虑第i个数,取或者不取,dp[i][j]表示在第i个数时,异或值为j的所有取法 ...

  5. hdu 4336 Card Collector (概率dp+位运算 求期望)

    题目链接 Card Collector Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  6. HDU 6186 CS Course (连续位运算)

    CS Course Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  7. HDU 5014 Number Sequence(位运算)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5014 解题报告:西安网赛的题,当时想到一半,只想到从大的开始匹配,做异或运算得到对应的b[i],但是少 ...

  8. hdu 5491 The Next (位运算)

    http://acm.hdu.edu.cn/showproblem.php?pid=5491 题目大意:给定一个数D,它的二进制数中1的个数为L,求比D大的数的最小值x且x的二进制数中1的个数num满 ...

  9. [poj 1185] 炮兵阵地 状压dp 位运算

    Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用&quo ...

随机推荐

  1. 详解CSS中clear属性both、left、right值的含义

    前几天一朋友在群里问clear:left的意思,我以为是简单的清除浮动问题,就让他百度"清除浮动",导致中间有点小误会.后来我按照他写的DEMO,发现我自己也没完全理解clear: ...

  2. Android中设定背景图片平铺。

    注:本文由Colin撰写,版权所有!转载请注明原文地址,谢谢合作! 在做Android开发时,我们常常需要为程序设定一个背景,但由于现在的Android设备尺寸不一,如果随便设置一个图片为背景,那么很 ...

  3. (免量产,免格式化)手动将PE安装到移动硬盘/U盘或无系统硬盘!

    在一台没有装系统的电脑上,只要把XP系统启动文件,及引导菜单文件(ntldr,boot.ini,”bootfont.bin这个可有可无,主要作用是显示中文菜单”)和GRUB引导文件和PE系统文件复制到 ...

  4. sql批量更换dedecms文章来源和作者

    前面写了一篇修改dedecms默认文章来源 "未知"改为关键词,那个是修改以后发布的文章“来源”才会变成自己设定的关键词,如果修改之前已经有很多文章了,那些文章“来源”还是显示“未 ...

  5. java中的方法重载与重写以及方法修饰符

    1. 方法重载Overloading , 是在一个类中,有多个方法,这些方法的名字相同,但是具有不同的参数列表,和返回值 重载的时候,方法名要一样,但是参数类型和参数个数不一样,返回值类型可以相同,也 ...

  6. 在同一个页面使用多个不同的jQuery版本,让它们并存而不冲突

    - jQuery自诞生以来,版本越来越多,而且jQuery官网的新版本还在不断的更新和发布中,现已经达到了1.6.4版本,但是我们在以前的项目中就已经使用了旧版本的jQuery,比如已经出现的:1.3 ...

  7. PHP Socket实现websocket(三)Stream函数

    除了socket函数也可以使用stream函数来实现服务器与客户端. 参考PHP 的Stream实现服务器客户端模型: http://php.net/manual/en/book.stream.php ...

  8. leetcode 236. Lowest Common Ancestor of a Binary Tree

    Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According ...

  9. angularjs入门基础一

    app.controller('firstController',function($scope,$rootScope){ $scope.name='张三'; $rootScope.age='30'; ...

  10. busybox microcom

    /************************************************************************* * busybox microcom * 说明: ...