题意:一个m行n列的图由#、*、o三种符号组成,分别代表冰山、海域、浮冰,问最多可放的炮舰数(要求满足以下条件)

1、炮舰只可放在海域处

2、两个炮舰不能放在同一行或同一列(除非中间隔着一个或多个冰山)

分析:

1、如果单纯只考虑不能放在同一行同一列,那就是行号与列号的匹配,原理与UVALive 6811 Irrigation Line(二分图最小点覆盖--匈牙利算法)相同。

2、但现在隔着冰山可以放置炮舰,那假设某一行被冰山分隔成两部分,这一行的前半部分和后半部分可以看做是两行,再应用“行号”与“列号”的匹配的原理

3、既然要行号与列号匹配,那就要分别按照行和列给图标号

举例如下:

(1)若按行,则将海域从1开始标号,如果是连续的海域那标号相同,若有冰山分隔,标号加1.

PS:例如第三行22#3,此处2是形式意义上的第二行,因为有上述放置炮舰的原则,可以理解为是可以放置炮舰的第2行,而由于有冰山分隔,所以这一行的前后互不干扰,因此3可以理解为是可以放置炮舰的第3行

(2)按列同理

4、理论上讲海域可以放置炮舰,也就是说,有标号的地方可以放置炮舰,每一个放置的地方都是一个行号与列号的匹配,由此可得如下匹配

5、一条连线代表一个可放置的炮舰,求最大匹配即可

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#define Min(a, b) a < b ? a : b
#define Max(a, b) a < b ? b : a
typedef long long ll;
typedef unsigned long long llu;
const int INT_INF = 0x3f3f3f3f;
const int INT_M_INF = 0x7f7f7f7f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const ll LL_M_INF = 0x7f7f7f7f7f7f7f7f;
const int dr[] = {, , -, };
const int dc[] = {-, , , };
const double pi = acos(-1.0);
const double eps = 1e-;
const int MAXN = + ;
const int MAXT = + ;
using namespace std;
char a[MAXN][MAXN];
int x[MAXN][MAXN];
int y[MAXN][MAXN];
int mp[MAXT][MAXT];
bool used[MAXT];
int match[MAXT];
int m, n, cnt1, cnt2;
void deal_row(){
cnt1 = ;
for(int i = ; i < m; ++i){
bool flag = false;
for(int j = ; j < n; ++j){
if(a[i][j] == '*'){
x[i][j] = cnt1;
flag = true;
}
if(a[i][j] == '#'){
++cnt1;
flag = false;
}
}
if(flag) ++cnt1;
}
}
void deal_column(){
cnt2 = ;
for(int i = ; i < n; ++i){
bool flag = false;
for(int j = ; j < m; ++j){
if(a[j][i] == '*'){
y[j][i] = cnt2;
flag = true;
}
if(a[j][i] == '#'){
++cnt2;
flag = false;
}
}
if(flag) ++cnt2;
}
}
bool Find(int x){
for(int i = ; i < cnt2; ++i){
if(mp[x][i] && !used[i]){
used[i] = true;
if(!match[i] || Find(match[i])){
match[i] = x;
return true;
}
}
}
return false;
}
void solve(){
int cnt = ;
for(int i = ; i < cnt1; ++i){
memset(used, false, sizeof used);
if(Find(i)) ++cnt;
}
printf("%d\n", cnt);
}
int main(){
int T;
scanf("%d", &T);
while(T--){
memset(a, , sizeof a);
memset(x, , sizeof x);
memset(y, , sizeof y);
memset(mp, , sizeof mp);
memset(match, , sizeof match);
scanf("%d%d", &m, &n);
for(int i = ; i < m; ++i)
scanf("%s", a[i]);
deal_row();
deal_column();
for(int i = ; i < m; ++i){
for(int j = ; j < n; ++j){
if(a[i][j] == '*'){
mp[x[i][j]][y[i][j]] = ;
}
}
}
solve();
}
return ;
}

HDU 5093 Battle ships(二分图最大匹配)的更多相关文章

  1. hdu 5093 Battle ships (二分图)

    二分图最大匹配问题 遇到冰山就把行列拆成两个部分.每个部分x也好,y也好只能匹配一次 图画得比较草,将就着看 横着扫一遍,竖着扫一遍,得到编号 一个位置就对应一个(xi,yi)就是X集到Y集的一条边, ...

  2. HDOJ 5093 Battle ships 二分图匹配

    二分图匹配: 分别按行和列把图展开.hungary二分图匹配. ... 例子: 4 4 *ooo o### **#* ooo* 按行展开. .. . *ooo o#oo oo#o ooo# **#o ...

  3. hdu 5093 Battle ships(二分图最大匹配)

    题意: M*N的矩阵,每个格子上是三个之一:*.o.#.                     (1 <= m, n <= 50) *:海洋,战船可以停在上面.      o:浮冰,战船 ...

  4. hdu 5093 Battle ships

    二分图匹配 #include<cstdio> #include<cstring> #include<iostream> #include<cmath> ...

  5. hdu 5093 Battle ships 匈牙利 很巧妙的建图思路

    //这题逼我把匈牙利学了 之前一直很勤快敲网络流 而且不以为耻反以为荣 解:首先按行扫描编号,如果在同一块中(即可以相互攻击),那么将其标为相同的数组,对列也做同样的操作. 然后扫描整张图,如果行编号 ...

  6. hdoj 5093 Battle ships 【二分图最大匹配】

    题目:pid=5093" target="_blank">hdoj 5093 Battle ships 题意:给你一个n*m的图,图中有冰山 '# ',浮冰 'o' ...

  7. Battle ships(二分图,建图,好题)

    Battle ships Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Tot ...

  8. HDU - 1045 Fire Net (二分图最大匹配-匈牙利算法)

    (点击此处查看原题) 匈牙利算法简介 个人认为这个算法是一种贪心+暴力的算法,对于二分图的两部X和Y,记x为X部一点,y为Y部一点,我们枚举X的每个点x,如果Y部存在匹配的点y并且y没有被其他的x匹配 ...

  9. hdu 1083 Courses(二分图最大匹配)

    题意: P门课,N个学生.     (1<=P<=100    1<=N<=300) 每门课有若干个学生可以成为这门课的代表(即候选人). 又规定每个学生最多只能成为一门课的代 ...

随机推荐

  1. javascript 拷贝

    拷贝简单分为浅拷贝与深度拷贝,即给定一个对象,生成一个相同的对象. 浅拷贝 function copy(source,destiny){ destiny = destiny || {}; if(typ ...

  2. 死锁相关 变量 与 PURGE 线程停止

    http://www.tuicool.com/articles/NzAFZn https://github.com/percona/percona-server/pull/83/commits/091 ...

  3. innodb_lru_scan_depth

    innodb_lru_scan_depth是5.6新增加的参数,根据 官方文档 描述,它会影响page cleaner线程每次刷脏页的数量, 这是一个每1秒  loop一次的线程.在Innodb内部, ...

  4. mysqldump 使用 --set-gtid-purged

    1.导出时指定字符集,报错Character set 'utf-8' is not a compiled character set and is not specifie .--default-ch ...

  5. JavaScript随机数

    function random(start,end){ var total=start+end; return Manth.floor(Manth.random()+total-start); }

  6. UITableView  折叠效果

    1:创建一个model数据模型 #import <Foundation/Foundation.h> @interface DataModel : NSObject //保存section中 ...

  7. [设计模式] .NET设计模式笔记 - 了解设计模式

    今天在TerryLee的cnblog(http://terrylee.cnblogs.com)里看到了与设计模式相关的整套文章,初学设计模式看完每篇文章后做些笔记和摘抄. ●什么是设计模式,什么是架构 ...

  8. [Java,JavaEE] 最常用的Java库一览

    引用自:http://www.importnew.com/7530.html 本文由 ImportNew - 邢 敏 翻译自 programcreek.欢迎加入Java小组.转载请参见文章末尾的要求. ...

  9. 3. Android框架和工具之 xUtils(ViewUtils )

    1. ViewUtils 作用: 完全注解方式就可以进行UI绑定和事件绑定. 无需findViewById和setClickListener等. 2. UI绑定 和 事件绑定 (1)UI绑定 下面我們 ...

  10. [经典算法] 排列组合-N元素集合的所有子集(一)

    题目说明: 给定一组数字或符号,产生所有可能的集合(包括空集合),例如给定1 2 3,则可能的集合为:{}.{1}.{1,2}.{1,2,3}.{1,3}.{2}.{2,3}.{3}. 题目解析: 如 ...