hdu 5093 Battle ships (二部图+最大匹配)

Battle ships

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 172    Accepted Submission(s): 84

Problem Description

Dear contestant, now you are an excellent navy commander, who is responsible of a tough mission currently.

Your fleet unfortunately encountered an enemy fleet near the South Pole where the geographical conditions are negative for both sides. The floating ice and iceberg blocks battleships move which leads to this unexpected engagement highly dangerous, unpredictable
and incontrollable.

But, fortunately, as an experienced navy commander, you are able to take opportunity to embattle the ships to maximize the utility of cannons on the battleships before the engagement.

The target is, arrange as many battleships as you can in the map. However, there are three rules so that you cannot do that arbitrary:

A battleship cannot lay on floating ice

A battleship cannot be placed on an iceberg

Two battleships cannot be arranged in the same row or column, unless one or more icebergs are in the middle of them.

Input

There is only one integer T (0<T<12) at the beginning line, which means following T test cases.

For each test case, two integers m and n (1 <= m, n <= 50) are at the first line, represents the number of rows and columns of the battlefield map respectively. Following m lines contains n characters iteratively, each character belongs to one of ‘#’, ‘*’,
‘o’, that symbolize iceberg, ordinary sea and floating ice.

Output

For each case, output just one line, contains a single integer which represents the maximal possible number of battleships can be arranged.

Sample Input

2
4 4
*ooo
o###
**#*
ooo*
4 4
#***
*#**
**#*
ooo#

Sample Output

3
5

题意 : 给你一张 n*m 的矩阵图形  ,‘ * ’ 表示 空地 , ‘ o ’ 表示浮冰  , ‘ # ’ 表示 冰山  , 你

可以在空地上方战舰 , 但是同一行或同一列只能放一个战舰。若两个战舰想放在同一行或同一

列上,那么它们之间必须要有冰山相隔。然后问你在这张图上最多可以放多少个战舰 ?

思路 :  二部图的最大匹配问题 ,将行和列方别当成一个集合 ,每一行和每一列方别当成对应

集合的点。若行或列中有 ’ # ‘ ,就把行或列拆点。 就以样例 一为例:

*ooo            行集合(将 ’ * ‘标号)        1ooo                   列集合       1ooo

o###                                                 o###                                     o###

**#*                                                   22#3                                     23#4

ooo*                                                  ooo4                                     ooo4

然后看原图 ’ * ‘ 的位置,就可以建图了 。

然后求出图的最大匹配就是答案了。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 55*30;
const int maxn = 55;

int a[maxn][maxn],b[maxn][maxn],match[N],n,m,p,q;
bool con[N][N],vis[N];
char ch[maxn][maxn];

void initial()
{
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    memset(con,0,sizeof(con));
    memset(match,-1,sizeof(match));
}

void input()
{
    scanf("%d %d",&n,&m);
    for(int i=0; i<n; i++)  scanf("%s",ch[i]);
}

void creat_row()
{
    p=1;
    bool flag;
    for(int i=0; i<n; i++)
    {
        flag=0;
        for(int j=0; j<m; j++)
        {
               if(ch[i][j]=='*')
               {
                   a[i][j]=p;
                   flag=1;
               }
               if(ch[i][j]=='#')
               {
                   p++;
                   flag=0;
               }
        }
        if(flag)  p++;
    }
}

void creat_column()
{
    q=1;
    bool flag;
    for(int j=0; j<m; j++)
    {
        flag=0;
        for(int i=0; i<n; i++)
        {
               if(ch[i][j]=='*')
               {
                   b[i][j]=q;
                   flag=1;
               }
               if(ch[i][j]=='#')
               {
                   q++;
                   flag=0;
               }
        }
        if(flag)  q++;
    }
}

bool dfs(int x)
{
    for(int i=1;i<q;i++)
    {
         if(!vis[i] && con[x][i])
         {
              vis[i]=1;
              if(match[i]==-1 || dfs(match[i]))
              {
                  match[i]=x;
                  return true;
              }
         }
    }
    return false;
}

void solve()
{
    creat_row();
    creat_column();
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
             if(ch[i][j]=='*')
                 con[a[i][j]][b[i][j]]=1;
    int cnt=0;
    for(int i=1;i<p;i++)
    {
        memset(vis,0,sizeof(vis));
        if(dfs(i))  cnt++;
    }
    printf("%d\n",cnt);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        initial();
        input();
        solve();
    }
    return 0;
}
时间: 2024-10-11 11:01:30

hdu 5093 Battle ships (二部图+最大匹配)的相关文章

hdu 5093 Battle ships 最大二分匹配

Battle ships Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 589    Accepted Submission(s): 233 Problem Description Dear contestant, now you are an excellent navy commander, who is responsible

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

题意: M*N的矩阵,每个格子上是三个之一:*.o.#.                     (1 <= m, n <= 50) *:海洋,战船可以停在上面.      o:浮冰,战船不可以停在上面      #:冰山,战船不可以停在上面. 限制:两艘战船不能处于同一行或同一列,除非它们之间有冰山挡着. 问最多可以停多少艘战船. 思路: 和二分图最小点覆盖那道经典题很相似.不过不是求最小点覆盖. 对于每一行,如果连续的一段只能放一艘战船,则将这一段视为同一个点.则每一行都被分为若干个小段,

hdu 5093 Battle ships 二分图匹配

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5093 一开始就往贪心的方向想了结果wa全场 这种矩阵形式的图一般要联想到行和列构成了二分图 然后实质就是求一个最大匹配 中间的冰山实际上就是把一行或一列切成多个顶点而已 所以一开始预处理一下 然后就可以套用模板 #include <cstring> #include <cstdlib> #include <cstring> #include <cmath> #i

hdu 5093 Battle ships二分图

二分图最大匹配问题 遇到冰山就把行列拆成两个部分.每个部分x也好,y也好只能匹配一次 图画得比较草,将就着看 横着扫一遍,竖着扫一遍,得到编号 一个位置就对应一个(xi,yi)就是X集到Y集的一条边, 由题意,每个点只能被选择一次.所以最大匹配的边数就是答案了. 算法过程 通常都是先贪心求一个匹配,然后开始增广. 寻找增广路的过程: 一个没有和任意边匹配的点叫做未盖点,从左集X中一个未盖点u出发寻找增广路. 从u出发,选一个非匹配边到达Y集中的v,如果v没匹配,那么就找到一条增广路(只要把之前走

hdu 5093 Battle ships 二分匹配

题意:在n×m的方格中,'#'代表iceberg,'*'代表ocean,'o'代表floating ice.战舰只能放在ocean上,在同一行或者同一列不能放两 个战舰除非它们中间有iceberg,求最多能放多少战舰. 思路:二分匹配.每行中连续为'*'的作为X集合中一个点,同样,将每列中连续为'*'的点作为Y集合中的一个点.对原图中每个'*',将其对应的X集合和Y集合中的标号建边,便形成了二分图,对该图求最大匹配.详见代码: /*********************************

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

//这题逼我把匈牙利学了 之前一直很勤快敲网络流 而且不以为耻反以为荣 解:首先按行扫描编号,如果在同一块中(即可以相互攻击),那么将其标为相同的数组,对列也做同样的操作. 然后扫描整张图,如果行编号为a的块与列编号为b的块有公共点,那么将二部图中A集合中a点与B集合中b点相连.最后求出来最大二分匹配数就是答案. (为什么这样做)首先很明显的,二部图中每一条边就对应原图中的一个点,因此,匹配数=边数=最多可放置的战舰数,另外二分图每个点只能匹配一次,对应到原题中就是每一块只能放置一个战舰. 1

hdu 5093 Battle ships

二分图匹配 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cmath> 5 #define maxn 60 6 #define maxd 1500 7 using namespace std; 8 int v[maxd][maxd],vist[maxd],math[maxd]; 9 10 int col[maxn][maxn],row[maxn][maxn]; 1

HDU 5093 Battle ships(二分图匹配)

该题是一道经典的二分图匹配题目 .  同一列(行)上不能放两个船除非有冰山隔着.对于这种二维平面图,我们很容易想到将行和列分成两个集合,进行二分图匹配,当一个行坐标匹配到一个列坐标时,该格子可以放置船.那么为了使任意两个船都不在同一行或者同一列,除非有冰山,我们可以将每一行中一块连续的只能放置一个船的区域都设成一个编号,同样的按照列也这样处理,这样就相当于将行和列缩点了,接下来用最大流模板套一套就可以了 . 处理二分图还有一种更好的算法,叫匈牙利算法,紫书上没有,先用最大流算法解决吧 . 紫书十

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

题目:hdoj 5093 Battle ships 题意:给你一个n*m的图,图中有冰山 '# ',浮冰 'o' 以及普通海 ' * ',现在要在海中布置尽可能多的炮弹,炮弹不能突波冰山,不能让炮弹互相攻击到,问最大能不知多少个? 分析:二分图的经典题目,关键在于怎么建图,图进行两次编号,按行编号,每一行中能攻击到的一块编号成相同的数,每一列同样,然后对行和列有编号的地方进行连边,求一次最大匹配即可,我用最大流求的最大匹配. AC代码: #include <cstdio> #include &