http://poj.org/problem?id=2226 (题目链接)

题意

  给出一个只包含‘.’和‘*’的矩阵,用任意长度的宽为1的木板覆盖所有的‘*’而不覆盖‘.’,木板必须跟矩形的长或宽平行。问最少需要多少块木板。

Solution

  这道题的构图非常巧妙,堪称经典构图。对于每一个‘*’,要么就是被横的木板覆盖,要么就是被竖的木板覆盖,而木板的长度一定都是取到最长(因为题目没有说木板不能重叠,所以木板尽可能长不会使答案变大)。

  假设我们全部用横木板进行覆盖,那么可以很简单的统计出哪些地方用第几块木板覆盖;同样如果我们全部用竖的木板进行覆盖,也可以统计出哪些地方用第几块木板覆盖。所以我们最后要选择的木板就在这些木板中产生。 
   
  拿样例来举个例子: 
               横:1 0 2 0   竖:1 0 4 0 
                 0 3 3 3     0 3 4 5 
                 4 4 4 0     2 3 4 0 
                 0 0 5 0     0 0 4 0 
   
  所以现在问题就转化成了如何选取最少的木板,使所有的‘*’都被覆盖。这是不是很像二分图匹配中的最小点覆盖,可问题是我们怎么对它构图呢?

  对于每一个‘*’,都会有一个横木板和竖木板在这个位置相交。那么如果我们对于每一个‘*’给在这里相交的横木板和竖木板的编号连一条边,是不是每一条边都表示一个‘*’呢?答案是显然的。问题到这里也就迎刃而解了。最小点覆盖=最大匹配数,所以我们只需要连完边后跑匈牙利就可以了。

代码

// poj2226
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#define LL long long
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
inline LL getint() {
int f,x=0;char ch=getchar();
while (ch<='0' || ch>'9') {if (ch=='-') f=-1;else f=1;ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
} const int maxn=1000;
struct edge {int to,next;}e[maxn*maxn];
int n,m,cnt,head[maxn],a[maxn][maxn],x[maxn][maxn],y[maxn][maxn],p[maxn],vis[maxn];
char s[maxn]; void insert(int u,int v) {
e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;
}
bool find(int x) {
for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to]) {
vis[e[i].to]=1;
if (p[e[i].to]==0 || find(p[e[i].to])) {
p[e[i].to]=x;
return 1;
}
}
return 0;
}
int main() {
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) {
scanf("%s",s);
for (int j=0;j<m;j++) {
if (s[j]=='*') a[i][j+1]=1;
else a[i][j+1]=0;
}
}
int xx=0,yy=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) if (a[i][j]>0) {
x[i][j]=++xx;
while (j<m && a[i][j+1]>0) {j++;x[i][j]=xx;}
}
for (int j=1;j<=m;j++)
for (int i=1;i<=n;i++) if (a[i][j]>0) {
y[i][j]=++yy;
while (i<n && a[i+1][j]>0) {i++;y[i][j]=yy;}
}
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (a[i][j]>0) insert(x[i][j],y[i][j]);
int ans=0;
for (int i=1;i<=xx;i++) {
for (int j=1;j<=yy;j++) vis[j]=0;
if (find(i)) ans++;
}
printf("%d\n",ans);
return 0;
}

  

【poj2226】 Muddy Fields的更多相关文章

  1. 【POJ2226】Muddy Fields

    题目大意:给定一个 N*M 的图,图中有一些格子不能被任何东西覆盖,现有一些宽度为 1,长度任意的骨牌覆盖这些可以被覆盖的格子,骨牌之间可以重叠,求将所有可以被覆盖的格子覆盖所需的最小骨牌数是多少. ...

  2. 【poj3254】Corn Fields 状态压缩dp

    AC通道:http://vjudge.net/problem/POJ-3254 [题目大意] 农夫约翰购买了一处肥沃的矩形牧场,分成M*N(1<=M<=12; 1<=N<=12 ...

  3. 【POJ3254】Corn Fields 状压DP第一次

    !!!!!!! 第一次学状压DP,其实就是运用位运算来实现一些比较,挺神奇的.. 为什么要发“!!!”因为!x&y和!(x&y)..感受一下.. #include <iostre ...

  4. 【poj3254】 Corn Fields

    http://poj.org/problem?id=3254 (题目链接) 题意 给出一块n*m的田地,有些能够耕种,有些不能.要求将牛两两不相邻的放在田中,牛的个数至少为1个.问有多少种放法. So ...

  5. 【POJ3254】Corn Fields

    http://poj.org/problem?id=3254 题意:给你一块n*m(0<n,m<=12)的地图,其中有的方格是肥沃的(用1表示),有的方格是贫瘠的(用0表示).现在约翰要在 ...

  6. 【POJ3254】Corn Fields(状压DP)

    题意: 一个M x N矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻.问有多少种放牛方案( ...

  7. 【BZOJ1725】[Usaco2006 Nov]Corn Fields牧场的安排 状压DP

    [BZOJ1725][Usaco2006 Nov]Corn Fields牧场的安排 Description Farmer John新买了一块长方形的牧场,这块牧场被划分成M列N行(1<=M< ...

  8. 【BZOJ】1725: [Usaco2006 Nov]Corn Fields牧场的安排

    [算法]状压DP [题解]对于上一行的每个状态,每行进行DFS. #include<cstdio> #include<algorithm> #include<cstrin ...

  9. 【USACO 2006 November Gold】Corn Fields

    [题目链接] 点击打开链接 [算法] 状压DP [代码] #include<bits/stdc++.h> using namespace std; #define MAXN 12 #def ...

随机推荐

  1. Hadoop 一二事(1) - 简单介绍与杂谈

    大数据大数据,身边很多朋友都在谈大数据,Big Data!!! 到底是什么,用来干嘛的,也很少有人说得出一二,那今天开始就简单说说这一二事吧 hadoop 的来源:是作者女儿的一个玩具 - 一只黄色的 ...

  2. The ServiceClass object does not implement the required method in the following form: OMElement sayHello(OMElement e)

    今天遇到一件诡异的事情,打好的同一个aar包,丢到测试环境tomcat,使用soapui测试,正常反馈结果. 丢到本地tomcat,使用soapui测试,始终报以下错误. <soapenv:En ...

  3. 系统级I/O学习记录

    重要知识点 输入/输出(I/O) I/O是主存和外部设备(如磁盘驱动器.终端和网络)之间拷贝数据的过程. 输入操作是从I/O设备拷贝数据到主存. 输出操作是从主存拷贝到I/O设备. Unix I/O ...

  4. Linux第二次报告20135221

    学习计时:共xxx小时 读书: 代码: 作业: 博客: 一.学习目标 1. 熟悉Linux系统下的开发环境   2. 熟悉vi的基本操作   3. 熟悉gcc编译器的基本原理   4. 熟练使用gcc ...

  5. 20145208《Java程序设计》第2周学习总结

    2015208 <Java程序设计>第2周学习总结 教材学习内容总结 本章内容主要讲了类型.变量与运算符的一些知识,也讲了一些基本的流程语法. 类型 基本类型 整数:short整数(占2字 ...

  6. VmWare Workstation 10 安装 Ubuntu 14.04 问题解决

    Ubuntu安装过程很顺利,安装完成后还是有小问题存在   问题1:无法联网,PING可以通,网址无法解析 原因:默认DNS设置不正确 解决:设置DNS地址为8.8.8.8,问题解决   问题2:vm ...

  7. Logparser 的用法

    Logparser是一款非常强大的日志分析软件,可以帮助你详细的分析网站日志.是所有数据分析和网站优化人员都应该会的一个软件.Logparser是微软的一款软件完全免费的,大家可以在微软的官网上去下载 ...

  8. 技术分析:Femtocell家庭基站通信截获、伪造任意短信

    阿里移动安全团队与中国泰尔实验室无线技术部的通信专家们一起,联合对国内运营商某型Femtocell基站进行了安全分析,发现多枚重大漏洞,可导致用户的短信.通话.数据流量被窃听.恶意攻击者可以在免费申领 ...

  9. 【android】TabLayout文字闪烁问题

    安卓MD设计提供了一个非常酷炫的效果,TabLayout拿来做选项卡时非常合适的,但是在实际使用中发现22.2.1版本号的TabLayout在ViewPager滑动的时候会出现闪烁现象. 解决方法:在 ...

  10. 初探Asp.net5

    说到Asp.net 5,确实让我有种激动的心情,微软的全力大招在一波一波的发出,也在牵动着每一个程序员的心.作为你们中的一员,在每次看到微软的新技术时,都满怀一种激动的心情,也同时希望微软在开源和跨平 ...