[codevs1050]棋盘染色 2

试题描述

有一个5*N的棋盘,棋盘中的一些格子已经被染成了黑色,你的任务是对最少的格子染色,使得所有的黑色能连成一块。

输入

第一行一个整数N(<=100),接下来N行每行一个长度为5的01串,1表示所在格子已经被染成了黑色,0表示所在格子没有被染色。

输出

输出最少需要对多少个格子进行染色

输入示例


输出示例


数据规模及约定

N(<=100)

题解

状压 dp 一下。设 f(i, S) 表示考虑前 i 行,最后一行情况为集合 S 的最小代价;其中 S 是一个 5 位的 4 进制数,若某一位为 0,则表示第 i 行对应的位置没有染色,若某一位为 x(0 < x < 4),则表示该位上有染色并且该位置所在的连通分量编号为 x(注意这里的连通分量是指考虑前 i 行时的连通性,因为最终要做到整个图被弄成一个连通分量,所以任意时刻同一连通块必定能够贯穿上下),一行中只有 5 个位置,所以最多产生 3 个连通块,也就是每一位上只可能是 0, 1, 2, 3,所以是 5 位的 4 进制数。

转移时枚举一下下一行在哪些位置染色,然后暴力搞一搞判一判就好了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 110
#define maxm 10
char Map[maxn][maxm];
int n, A[maxn][maxm], f[maxn][1030], now[maxm], lst[maxm], fin[maxm], tfin[maxm]; bool iszero(char* S) {
int l = strlen(S);
for(int i = 0; i < l; i++) if(S[i] - '0') return 0;
return 1;
}
int bitcal(int S) {
int cnt = 0;
while(S) cnt += (S & 1), S >>= 1;
return cnt;
}
void Up(int& a, int b) {
if(a < 0) a = b;
else a = min(a, b);
return ;
} void show(int T[]) {
for(int i = 0; i < 5; i++) printf("%d%c", T[i], i < 4 ? ' ' : '\n');
return ;
} int main() {
n = read();
for(int i = 1; i <= n; i++) scanf("%s", Map[i]); int up = 1, down = n, cnt = 0;
while(iszero(Map[up])) up++;
while(iszero(Map[down])) down--;
for(int i = up; i <= down; i++) {
cnt++;
for(int j = 0; j < 5; j++) A[cnt][j] = Map[i][j] - '0';
}
memset(f, -1, sizeof(f));
f[0][0] = 0;
int all = (1 << 5) - 1, All = (1 << 10) - 1;
for(int i = 1; i <= cnt; i++) {
int reaS = 0;
for(int j = 4; j >= 0; j--) reaS = reaS << 1 | A[i][j];
for(int S = 0; S <= all; S++) if((reaS | S) == S) {
int cnt1 = bitcal(reaS ^ S);
for(int j = 0; j < 5; j++) now[j] = S >> j & 1;
for(int tS = 0; tS <= All; tS++) if(f[i-1][tS] >= 0) {
int tmpS = tS;
for(int j = 0; j < 5; j++) lst[j] = tmpS % 4, tmpS >>= 2;
int mx = 0;
for(int j = 0; j < 5; j++) if(now[j]) {
if(!j) mx = fin[j] = 1;
else if(!fin[j-1]) fin[j] = ++mx;
else fin[j] = fin[j-1];
}
else fin[j] = 0;
// printf("%d _fin: ", cnt1); show(fin);
mx = 0;
for(int j = 0; j < 5; j++) mx = max(mx, lst[j]);
int has[maxm]; memset(has, 0, sizeof(has));
for(int j = 0; j < 5; j++) if(lst[j]) {
if(!has[lst[j]] && fin[j]) has[lst[j]] = fin[j];
else if(fin[j]) {
fin[j] = has[lst[j]];
for(int x = j - 1; x >= 0 && fin[x]; x--) fin[x] = has[lst[j]];
for(int x = j + 1; x < 5 && fin[x]; x++) fin[x] = has[lst[j]];
}
}
bool ok = 1;
for(int j = 1; j <= mx; j++) if(!has[j]) {
ok = 0; break;
}
if(!ok) continue;
for(int j = 0; j < 5; j++) tfin[j] = fin[j];
sort(tfin, tfin + 5);
int x = unique(tfin, tfin + 5) - tfin;
if(x > 1) for(int j = 0; j < 5; j++) fin[j] = lower_bound(tfin, tfin + x, fin[j]) - tfin;
// show(now); show(lst); show(fin);
tmpS = 0;
for(int j = 4; j >= 0; j--) tmpS = tmpS << 2 | fin[j];
Up(f[i][tmpS], f[i-1][tS] + cnt1);
// printf("%d\n", f[i][tmpS]); putchar('\n');
}
}
} int ans = -1;
for(int S = 0; S <= all; S++) {
for(int i = 0; i < 5; i++) now[i] = S >> i & 1;
int reaS = 0;
for(int i = 4; i >= 0; i--) reaS = reaS << 2 | now[i];
if(f[cnt][reaS] >= 0) Up(ans, f[cnt][reaS]);
}
printf("%d\n", ans); return 0;
}

写个状压 dp 真费劲。。。

[codevs1050]棋盘染色 2的更多相关文章

  1. [CodeVs1050]棋盘染色2(状态压缩DP)

    题目大意:有一个5*N(≤100)的棋盘,棋盘中的一些格子已经被染成了黑色,求最少对多少格子染色,所有的黑色能连成一块. 这题卡了我1h,写了2.6k的代码,清明作业一坨还没做啊...之前一直以为这题 ...

  2. codevs——1049 棋盘染色

    1049 棋盘染色  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description 有一个5×5的棋盘,上面有一 ...

  3. 【wikioi】1049 棋盘染色(迭代深搜)

    http://www.wikioi.com/problem/1049/ 这题我之前写没想到迭代加深,看了题解,然后学习了这种搜索(之前我写的某题也用过,,但是不懂专业名词 囧.) 迭代加深搜索就是限制 ...

  4. codevs 1049 棋盘染色

    题目描述 Description 有一个5×5的棋盘,上面有一些格子被染成了黑色,其他的格子都是白色,你的任务的对棋盘一些格子进行染色,使得所有的黑色格子能连成一块,并且你染色的格子数目要最少.读入一 ...

  5. 1050 棋盘染色 2 - Wikioi

    题目描述 Description 有一个5*N的棋盘,棋盘中的一些格子已经被染成了黑色,你的任务是对最少的格子染色,使得所有的黑色能连成一块. 输入描述 Input Description 第一行一个 ...

  6. HDU 5402 Travelling Salesman Problem(棋盘染色 构造 多校啊)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5402 Problem Description Teacher Mai is in a maze wit ...

  7. CODEVS——T 1049 棋盘染色

    http://codevs.cn/problem/1049/  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Descr ...

  8. hdu5601-N*M bulbs(黑白棋盘染色)

    一个矩形,一个人从左上角走到右下角,每走过一个位置把0变成1,1变成0. 求有没有可能他离开之后所有的数都是0 假设这个矩形是一个棋盘,黑白相间. 这样会发现从一个颜色走到相同颜色可以对棋盘不产生任何 ...

  9. [codevs1049]棋盘染色<迭代深搜>

    题目链接:http://codevs.cn/problem/1049/ 昨天的测试题里没有打出那可爱的迭代深搜,所以今天就来练一练. 这道题其实我看着有点懵,拿着题我就这状态↓ 然后我偷偷瞄了一眼hz ...

随机推荐

  1. (025)[系统故障]XP下禁止将串口设备识别成鼠标(转)

    很多人都遇到过这种问题:Windows XP启动时将一台连续发送数据的串口设备识别成串口鼠标,自动安装了串口鼠标驱动,而设备因此无法正常工作,而光标则无规律地到处跑.对此问题,Internet上的方法 ...

  2. 几种创建线程方式Thread类和Runnable接口

    对于很多想学习java的人来说,经常听别人说线程难,其实真正理解了线程后,一点都不会觉得线程难,这里我为大家梳理下线程的创建方式吧. 一.线程的创建方式有三种 1.继承Thread类 2.实现Runn ...

  3. css实现行内文字垂直居中

    之前本人一直使用浮动.相对定位.绝对定位和display:table等css的方法进行定位.网上得知flex可实现弹性布局,符合未来发展趋势,随尝试. 1:让盒子行内文字垂直居中,解决思路是讲文字的行 ...

  4. B树、B+树、红黑树、AVL树

    定义及概念 B树 二叉树的深度较大,在查找时会造成I/O读写频繁,查询效率低下,所以引入了多叉树的结构,也就是B树.阶为M的B树具有以下性质: 1.根节点在不为叶子节点的情况下儿子数为 2 ~ M2. ...

  5. Ubuntu docker 使用命令 系列二

    1.下载官方远程仓下的镜像:sudo docker pull <docker 镜像> ,sudo docker pull centos (没有指定版本,就是下载的最新的os) 2. 下载某 ...

  6. The Performance Manifesto

    Manifesto For Performance Testing And Engineering We choose to support others in their quest for bet ...

  7. Thrift入门及Java实例演示【转】

    概述 Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发.它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++.Java.Python.PHP.Ruby.Erlang.Perl.Ha ...

  8. ICEcoder显示汉字出现乱码的处理

    在网上看到icecoder这个小东西,是一个基于web的编辑器,很不错.唯一的缺点是打开的文件中汉字会变成乱码. 经查看源代码,在lib/file-control.php中,第89行是: echo ' ...

  9. 什么是Entitlement

    Entitlement(权限),可以想象成App里用于描述该App可以调用哪些服务的字符串.苹果的操作系统(mac os或者iOS)会通过检查这个串,决定这个应用是否可以调用相关功能.比如iCloud ...

  10. pagehelper 分页

    分页jar包: <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pa ...