UVA 10572 Black & White (状压DP)
题意:有一个n*m的矩阵,其中部分格子已经涂黑,部分涂白,要求为其他格子也上黑/白色,问有多少种涂法可以满足一下要求:
(1)任意2*2的子矩阵不可以同色。
(2)所有格子必须上色。
(3)只能有两个连通分量(即1黑1白)。
注:1<n,m<9。若能满足,顺便输出任一种涂色方法。
思路:
本来题也不难,只是刚开始写最小表示法,加上这题的难度,所以搞非常久。注:本题用最小表示法比较好。
大概逻辑如下:
if g[i][j]非首列且2*2子矩阵同色 then 非法状态;
if 上格连通分量不会丢失. then 合格状态;
然后对矩阵最后的两个格子特判如下(合法状态指的是对当前格子合法):
1)倒数第2格子的判断:
(1)if g[i][j]与上格同色 then 合法状态;
(2) if 上格的连通分量编号在轮廓线上并不是唯一 then 合法状态;
(3) if 轮廓线上所有格子颜色相同 then 合法状态;
2)倒数第1格子的判断:
(1)if 先尝试上面3种情况,若合法,再继续。
(2)if n=2 or 最后一个格子与上/左格(任一个以上都行)连通 then 合法状态;
当扫完所有格子后,将所有合法中连通分量最多为2个的都是符合要求的。路径记录只需要用一个64位整型来记录即可,较简单。
#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
#define ULL unsigned long long
using namespace std;
const int N=;
int g[N][N], code[N],color[N], cur, n, m;
int num[N]; //用于最小表示法
char str[N][N]; //用于路径输出
struct Hash_Map
{
static const int mod=;
static const int NN=;
int head[mod]; //桶指针
int next[NN]; //记录链的信息
LL status[NN]; //状态
LL value[NN]; //状态对应的DP值
ULL path[NN]; //路径的状态
int size; void clear()
{
memset(head, -, sizeof(head));
size = ;
} void insert(LL st, LL val,ULL p)
{
int h = st%mod;
for(int i=head[h]; i!=-; i=next[i])
{
if(status[i] == st)
{
value[i] += val;
path[i] = p; //任一路径
return ;
}
}
status[size]= st;
value[size] = val;
path[size] = p;
next[size] = head[h] ;
head[h] = size++;
}
}hashmap[]; LL encode() //编码
{
memset(num,-,sizeof(num));
LL s=;
for(int i=m-,cnt=; i>=; i--)
{
if(num[code[i]]<) num[code[i]]=cnt++;
s<<=;
s+=(num[code[i]]&)+color[i]*; //最高位为颜色,低3位为轮廓线
}
s<<=;
s+=color[m]; //color[m]放在最低位,方便处理。
return s;
} void decode(LL s) //解码:1个颜色位+3个状态位表示一个格子状态
{
color[m+]=(s&);s>>=;
for(int i=; i<=m; i++) //解码到code[1~m]上面,就不用移动。
{
code[i]=(s&); s>>=;
color[i]=(s&); s>>=;
}
} inline bool isunique() //判断上格子的连通分量是否唯一。
{
for(int i=; i<m; i++) if( code[i]==code[m] ) return false;
return true;
}
inline bool samecolor() //轮廓线上除了color[m]外,所有格子是否同色
{
for(int i=; i<m; i++) if(color[i]!=color[i-]) return false;
return true;
} void comb(int c,int j) //合并连通分量
{
if( c==color[m] ) code[]=code[m]; //与上同色
else code[]=;
if(j> && c==color[] ) //与左同色
{
int t=code[];
for(int i=; i<m; i++) if( code[i]==t ) code[i]=code[];
}
} void trycover(int c,LL v,ULL p,int i,int j) //尝试对g[i,j]涂c色
{
if( j> && color[]==c && color[m+]==c && color[m]==c ) return ; //2*2同色
color[]=c&;
if(i+==n && j+==m) //最后2格特处理
{
if( c==color[m] || !isunique() || samecolor() )
{
comb(c,j);
hashmap[cur].insert(encode(), v, p);
}
}
else if(i+==n && j+==m)//最后1格特处理
{
if( c==color[m] || !isunique() || samecolor() )
{
if(i<|| c==color[m]||c==color[]) //如果是m=2的矩阵,需要特别注意最后两个格子。
{
comb(c,j);
hashmap[cur].insert(encode(), v, p);
}
}
}
else
{
if( c!=color[m] && isunique() ) return ; //连通分量消失
comb(c,j);
hashmap[cur].insert(encode(), v, p);
}
} void cal()
{
hashmap[cur=].clear();
for(int i=; i<(<<m); i++ ) //产生第1行的所有情况。
{
color[m]=;
bool flag=;
for(int j=,t=i; j<m; j++,t>>=) //判断是否冲突。
{
color[j]=(t&);
if(g[][m--j]< && g[][m--j]!=color[j]) flag=; //注意点
}
if(flag)
{
code[m-]=;
for(int j=m-,up=; j>=; j--)
if(color[j]==color[j+]) code[j]=code[j+];
else code[j]=++up;
hashmap[].insert(encode(), , i);
}
} for(int i=; i<n; i++) //穷举剩下所有格子。
{
for(int j=; j<m; j++)
{
cur^=;
hashmap[cur].clear();
for(int k=; k<hashmap[cur^].size; k++)
{
LL s=hashmap[cur^].status[k];
LL v=hashmap[cur^].value[k];
ULL p=hashmap[cur^].path[k];
decode(s);
p<<=;
if( g[i][j]== )
{
trycover(,v,p+,i,j);
trycover(,v,p+,i,j);
}
else trycover(g[i][j],v,p+g[i][j],i,j);
}
}
}
} void print() //答案及路径输出。
{
int ans=;ULL mapp=;
for(int i=; i<hashmap[cur].size; i++)
{
int big=;
decode(hashmap[cur].status[i]);
for(int y=; y<=m; y++) big=max(big, code[y]); //求最大编号
if(big<=)
{
mapp=hashmap[cur].path[i];
ans+=hashmap[cur].value[i];
}
}
printf("%d\n", ans);
if(ans)
{
memset(str,'\0',sizeof(str));
for(int i=n-; i>=; i--)
{
for(int j=m-; j>=; j--)
{
if(mapp&) str[i][j]='#';
else str[i][j]='o';
mapp>>=;
}
}
for(int i=; i<n; i++) printf("%s\n",str[i]);
}
} int main()
{
freopen("input.txt", "r", stdin);
int t;cin>>t;
while(t--)
{
memset(g,,sizeof(g));
scanf("%d%d", &n,&m);
for(int i=; i<n; i++)
{
for(int j=; j<m; j++)
{
char c=getchar();
if(c=='#') g[i][j]=; //黑色
else if(c=='o') g[i][j]=;
else if(c=='.') g[i][j]=;
else j--;
}
}
cal();print();printf("\n");
}
return ;
}
AC代码
UVA 10572 Black & White (状压DP)的更多相关文章
- UVa 1204 Fun Game (状压DP)
题意:有一些小孩(至少两个)围成一圈,有 n 轮游戏,每一轮从某个小孩开始往左或者往右伟手帕,拿到手帕写上自己的性别(B,G),然后以后相同方向给下一个. 然后在某个小孩结束,给出 n 轮手帕上的序列 ...
- UVa 11825 Hackers' Crackdown (状压DP)
题意:给定 n 个计算机的一个关系图,你可以停止每台计算机的一项服务,并且和该计算机相邻的计算机也会终止,问你最多能终止多少服务. 析:这个题意思就是说把 n 台计算机尽可能多的分成一些组,使得每组的 ...
- UVa 1252 Twenty Questions (状压DP+记忆化搜索)
题意:有n件物品,每件物品有m个特征,可以对特征进行询问,询问的结果是得知某个物体是否含有该特征,要把所有的物品区分出来(n个物品的特征都互不相同), 最小需要多少次询问? 析:我们假设心中想的那个物 ...
- UVA - 1252 Twenty Questions (状压dp+vis数组加速)
有n个物品,每个物品有m个特征.随机选择一个物品让你去猜,你每次可以询问一个特征的答案,问在采取最优策略时,最坏情况下需要猜的次数是多少. 设siz[S]为满足特征性质集合S的特征的物品总数,dp[S ...
- UVA 11825 Hackers’ Crackdown 状压DP枚举子集势
Hackers’ Crackdown Miracle Corporations has a number of system services running in a distributed com ...
- UVA 1412 Fund Management (预处理+状压dp)
状压dp,每个状态可以表示为一个n元组,且上限为8,可以用一个九进制来表示状态.但是这样做用数组开不下,用map离散会T. 而实际上很多九进制数很多都是用不上的.因此类似uva 1601 Mornin ...
- 状压DP UVA 10817 Headmaster's Headache
题目传送门 /* 题意:学校有在任的老师和应聘的老师,选择一些应聘老师,使得每门科目至少两个老师教,问最少花费多少 状压DP:一看到数据那么小,肯定是状压了.这个状态不好想,dp[s1][s2]表示s ...
- UVa 11825 (状压DP) Hackers' Crackdown
这是我做状压DP的第一道题,状压里面都是用位运算来完成的,只要耐下心来弄明白每次位运算的含义,还是容易理解的. 题意: 有编号为0~n-1的n台服务器,每台都运行着n中服务,每台服务器还和若干台其他服 ...
- UVA - 1252 Twenty Questions (状压dp)
状压dp,用s表示已经询问过的特征,a表示W具有的特征. 当满足条件的物体只有一个的时候就不用再猜测了.对于满足条件的物体个数可以预处理出来 转移的时候应该枚举询问的k,因为实际上要猜的物品是不确定的 ...
- 状压dp的题目列表 (一)
状压dp的典型的例子就是其中某个数值较小. 但是某个数值较小也不一定是状压dp,需要另外区分的一种题目就是用暴力解决的题目,例如UVA818 紫书215 题目列表: ①校长的烦恼 UVA10817 紫 ...
随机推荐
- Win 7下破解Loadrunner 11(带中文版下载地址)
空间管理您的位置: 51Testing软件测试网 » 测试是一种生活态度 » 日志 与您一起分享在测试过程中的快乐与辛酸... Win 7下破解Loadrunner 11(带中文版下载地址) 上一篇 ...
- 使用 StoryBoard 制作一个能够删除cell的TableView
本篇博客方便自己检索使用.资源链接 下面是制作效果图,点击删除按钮,就能将该cell删除: 下面是主要的代码: #define KSUPER_TAG 20000 #define KDEFAU_TAG ...
- php破解防盗链技术
php破解防盗链技术 发送http请求 构造referer信息 在Http协议中,头信息里,有一个重要的选项: Referer Referer: 代表网页的来源,即上一页的地址 具体方法http.cl ...
- jQuery 设置图片 src 的2种方法
// 方法1 $('#imgValidateCode').attr("src", data.CodeUrl); // 方法2 var self = $("#refresh ...
- lightoj 1422【区间DP·分类区间首元素的情况】
题意: 给你n天分别要穿的衣服种类,可以套着穿, 一旦脱下来就不能再穿,求n天至少要几件. 思路: 区间DP dp[i][j]代表i到j需要至少几件衣服 第i天的衣服在第i天穿上了,dp[i][j]= ...
- lightoj1064 【DP求方案】
题意: n个相同的骰子,问你掷出>=x点数的可能性: 思路: dp[i][j]代表前 i 个骰子掷出 j 点数的方案数; 然后Σdp[n][x]-dp[n][6*n]就好了 卧槽,一开始想的是拆 ...
- [Xcode 实际操作]一、博主领进门-(6)Xcode的iOS模拟器的基本使用方法
目录:[Swift]Xcode实际操作 本文将演示Xcode的iOS模拟器的基本使用方法. 在项目导航区,鼠标右键[Assets.xcassets]资源文件夹. 隔壁右侧区域左下角点击[+],打开资源 ...
- webSocket的学习以及问题的解决
查过很多资料,感觉大部分都讲的不够详细,做为一个新人我从webSocket的基本开始学起, 首先webSocket的原理其实和Http差不多,但是由于Http只能被动的去向服务器请求消息,导致缺点太明 ...
- [Swift]快速反向平方根 | Fast inverse square root
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- ADO学途 three day
1· 程序的根本----数据 一个程序是用来处理数据算法的具体表现,可以说没有数据,程序就没有意义.今天主 要分享在一个程序中数据的支持者SQL server的建立和使用.首先当然不可缺少SQL se ...