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 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

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5093

题意:选尽可能多*号点,要求选得点之间必须有#阻隔,否者不能在同一行或者同一列。

做法:

先要把竖向*和O相连的 都连成一起,并编号。

然后是横着的也一样。

案例编号后:

2

4 4

*ooo

o###

**#*

ooo*

这里是竖向编号,同编号为一块

1 2 4 6

1 0 0 0

1 3 0 7

1 3 5 7

这里是横向编号

1 1 1 1

2 0 0 0

3 3 0 4

5 5 5 5

3

4 4

#***

*#**

**#*

ooo#

1 2 4 6

1 0 4 6

1 3 0 6

1 3 5 7

1 1 1 1

2 0 3 3

4 4 0 5

6 6 6 5

5

然后把竖向的每一块 都看作二分图左边的每一个点,

然后把横向的每一块 都看作二分图右边的每一个点,

星号必会对应一个竖向的块 编号,   和一个横向的块编号。

把每个星号对应的 两个编号连线。

如果匹配了,就表示这两个块都被占据了,这两个块就不能再有其他星号点被连了。

所以要知道最多有多少*可以放,就只用知道最多可以有几条边可以选。也就是求最大二分匹配了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <malloc.h>
#include <ctype.h>
#include <math.h>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#include <stack>
#include <queue>
#include <vector>
#include <deque>
#include <set>
#include <map> 

#define N 3000
int visit[N];
int mark[N];
int match[N][N];
int n,m,k;
int dfs(int x)
{
    int i;
	//printf("%d\n",x);
    for(i=1;i<=m;i++)//对左边的节点x与右边的节点进行逐一检查
    {
        if(!visit[i]&&match[x][i])
        {
            visit[i]=1;//标记检查过的点
            if(mark[i]==-1||dfs(mark[i])) //mark如果没男的,就直接给个老公,如果已经有老公,搜他老公有没有喜欢的,有的话,该女配新男;;;
            {//|| 前面过了 后面不运行;;
                mark[i]=x;//修改匹配关系
                return 1;
            }
        }
    }
    return 0;
}

int hungary ()
{
    memset(mark,-1,sizeof(mark));
	int maxx=0,j;
    for(j=1;j<=n;j++)//对做部分顶点逐个进行遍历
	{
		memset(visit,0,sizeof(visit));
		if(dfs(j))
			maxx++;
	}
	return maxx;
}

char mp[60][60];

int cdh[60][60];

int cds[60][60];
int main()//注意 mark[m]=n  mark[j] = i
{
    int maxx;
	int nn,mm;
	int t;
	scanf("%d",&t);
    while(t--)   //k 个配
    {
		scanf("%d%d",&nn,&mm);

		/*
		for(int i=0;i<nn;i++)
		{
			for(int j=0;j<mm;j++)
			{
				if((i+j)%2==1)
					mp[i][j]='#';
				else
					mp[i][j]='*';
			}
		}*/

		for(int i=0;i<nn;i++)
		{
			scanf("%s",mp[i]);
		}

		int sqi=0;
		for(int j=0;j<mm;j++)//左竖着
		{
			for(int i=0;i<nn;i++)
			{
				if(mp[i][j]!='#')
				{
					if(i==0)
						cds[i][j]=++sqi;
					else if(mp[i-1][j]=='#')
						cds[i][j]=++sqi;
					else
						cds[i][j]=sqi;

				}
			}
		}
		n=sqi;

		int hqi=0;
		for(int i=0;i<nn;i++) //you heng 着
		{
			for(int j=0;j<mm;j++)
			{
				if(mp[i][j]!='#')
				{
					if(j==0)
						cdh[i][j]=++hqi;
					else if(mp[i][j-1]=='#')
						cdh[i][j]=++hqi;
					else
						cdh[i][j]=hqi;
				}
			}
		}
		m=hqi;

		/*
		for(int i=0;i<nn;i++)//左竖着
		{
			for(int j=0;j<mm;j++)
			{
				printf("%d ",cdh[i][j]);

			}
			puts("");
		}

		*/

        memset(match,0,sizeof(match));

		for(int i=0;i<nn;i++)
		{
			for(int j=0;j<mm;j++)
			{
				if(mp[i][j]=='*')
				{
					int z=cds[i][j];
					int y=cdh[i][j];
					match[z][y]=1;
				}
			}
		}
		maxx=hungary();
        printf ("%d\n",maxx);

		/*

		scanf ("%d%d%d",&n,&m,&k)!=EOF
        for(i=1;i<=k;i++)
        {
            int a,b;
            scanf ("%d%d",&a,&b);
            match[a][b]=1;//标记当前匹配关系
        }
		max=hungary();
        printf ("%d\n",max);*/
    }
    return 0;
}
 
时间: 2024-12-19 01:21:40

hdu 5093 Battle ships 最大二分匹配的相关文章

HDU 5093 Battle ships(二分图匹配)

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

hdu 5093 Battle ships 二分匹配

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

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 o

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

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

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

二分图匹配 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二分图

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

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

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

hdu 2768 Cat vs. Dog (二分匹配)

Cat vs. Dog Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1422    Accepted Submission(s): 534 Problem Description The latest reality show has hit the TV: ``Cat vs. Dog''. In this show, a bunch