HDU 1045 Fire Net 二分图Bipartite题解

本题可以使用DFS直接爆搜出答案,不过这样类型的题目其实是个二分图的题解。

这个二分图,难不在Hungary算法,而是难在于建图。需要挺高的抽象思维的。

建图:

1 把同一行不被X分开的格子标同一个号码,被X分开的标下一个号码,这样做是为了缩点,不需要把所有的格子都分开标号,而且可以更方便建个更加小的图。

2 同理把同一列的格子标号

3 然后判断相同一个格子的行标号和列标号是有路径的,其他不在同一个格子的都是没有路径的。

4 这样就等于以行标号和列标号作为左右顶点,构建成一个二分图了

然后使用Hungary算法求二分图的最大匹配了。

真是非常巧妙的建模!

自己直接研究不出来,也是参考了别人的代码然后直接敲出来了。

做人要厚道,还是给个链接吧:http://www.cnblogs.com/kuangbin/archive/2011/08/09/2132830.html 不过他的是纯代码了,没说什么建模的。

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

int uN, vN;
int g[20][20];
int linker[20];
bool used[20];
char gra[5][5];
int graR[5][5];
int graL[5][5];

bool dfs(int u)
{
	for (int v = 1; v <= vN; v++)
	{
		if (g[u][v] && !used[v])
		{
			used[v] = true;
			if (-1 == linker[v] || dfs(linker[v]))
			{
				linker[v] = u;
				return true;
			}
		}
	}
	return false;
}

int hungary()
{
	int res = 0;
	for (int i = 0; i < 20; i++)
	{
		linker[i] = -1;
	}
	for (int u = 1; u <= uN; u++)
	{
		memset(used, 0, sizeof(used));
		if (dfs(u)) res++;
	}
	return res;
}

int main()
{
	int n;
	while (scanf("%d", &n) && n)
	{
		memset(graL, 0, sizeof(graL));
		memset(graR, 0, sizeof(graR));
		memset(g, 0, sizeof(g));

		getchar();
		for (int i = 0; i < n; i++)
		{
			gets(gra[i]);
		}
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				if (gra[i-1][j-1] == 'X')
					graL[i][j] = graR[i][j] = -1;
			}
		}
		vN = uN = 0;
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				while (graR[i][j] == -1 && j <= n) j++;
				if (j > n) break;
				uN++;
				while (graR[i][j] != -1 && j <= n)
				{
					graR[i][j] = uN;
					j++;
				}
			}
		}

		for (int j = 1; j <= n; j++)
		{
			for (int i = 1; i <= n; i++)
			{
				while (graL[i][j] == -1 && i <= n) i++;
				if (i > n) break;
				vN++;
				while (graL[i][j] != -1 && i <= n)
				{
					graL[i][j] = vN;
					i++;
				}
			}
		}

		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				if (graR[i][j] != -1) g[graR[i][j]][graL[i][j]] = 1;
			}
		}
		printf("%d\n", hungary());
	}
	return 0;
}

本题一开始我是用DFS爆搜过了,因为数据一看这么少,肯定可以过的。不过本题爆搜好像也不太容易一次AC,本人一开始就没思考好,用错了思路,WA了几次,不画图模拟,出错的几率还是相当高的。

const int MAX_N = 8;
char Maze[MAX_N][MAX_N];
int N;

bool isLegal(int r, int c)
{
	if (Maze[r][c] != '.') return false;
	bool legal = true;
	for (int i = r-1; i >= 0 && legal; i--)
	{
		if (Maze[i][c] == 'X') break;
		else if (Maze[i][c] != '.') legal = false;
	}
	for (int i = r+1; i < N && legal; i++)
	{
		if (Maze[i][c] == 'X') break;
		else if (Maze[i][c] != '.') legal = false;
	}
	for (int j = c-1; j >= 0 && legal; j--)
	{
		if (Maze[r][j] == 'X') break;
		else if (Maze[r][j] != '.') legal = false;
	}
	for (int j = c+1; j < N && legal; j++)
	{
		if (Maze[r][j] == 'X') break;
		else if (Maze[r][j] != '.') legal = false;
	}
	return legal;
}

int ans;
void dfs(int one = 0)
{
	bool flag = false;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			if (isLegal(i, j))
			{
				flag = true;
				Maze[i][j] = '@';
				dfs(one+1);
				Maze[i][j] = '.';
			}
		}
	}
	if (flag)
	{
		ans = max(ans, one+1);//, cout<<one<<endl;;
	}
}

int main()
{
	while (~scanf("%d", &N) && N)
	{
		while (getchar() != '\n') ;
		for (int i = 0; i < N; i++)
		{
			gets(Maze[i]);
		}
		ans = 0;
		dfs();
		printf("%d\n", ans);
	}
	return 0;
}
时间: 2024-10-06 01:21:00

HDU 1045 Fire Net 二分图Bipartite题解的相关文章

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

(点击此处查看原题) 匈牙利算法简介 个人认为这个算法是一种贪心+暴力的算法,对于二分图的两部X和Y,记x为X部一点,y为Y部一点,我们枚举X的每个点x,如果Y部存在匹配的点y并且y没有被其他的x匹配,那就直接匹配:如果Y中已经没有可以和x匹配的点(包括可以匹配的点已经被其他的x匹配),那就让已经匹配的y的原配x'寻找其他可以匹配的y’,并将y和x匹配,最后,统计出匹配的对数 (详细了解的话,可以看看这位的博客:https://blog.csdn.net/sunny_hun/article/de

HDU 1045 - Fire Net (最大独立集)

题意:给你一个正方形棋盘.每个棋子可以直线攻击,除非隔着石头.现在要求所有棋子都不互相攻击,问最多可以放多少个棋子. 这个题可以用搜索来做.每个棋子考虑放与不放两种情况,然后再判断是否能互相攻击来剪枝.最后取可以放置的最大值. 这里我转化成求最大独立集来做. 首先将每个空地编号,对于每个空地,与该位置可以攻击到的空地连边.找最多的空地使得不互相攻击,即求该图的最大独立集.与搜索做法基本一致,但是说法略有不同. 1 #include<iostream> 2 #include<cstring

HDU 1045 Fire Net 贪心

Problem Description Suppose that we have a square city with straight streets. A map of a city is a square board with n rows and n columns, each representing a street or a piece of wall. A blockhouse is a small castle that has four openings through wh

HDU 1045 Fire Net 状压暴力

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1045 Fire Net Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 8073    Accepted Submission(s): 4626 Problem Description Suppose that we have a squar

hdu 1045 Fire Net(最小覆盖点+构图(缩点))

http://acm.hdu.edu.cn/showproblem.php?pid=1045 Fire Net Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 1045 Description Suppose that we have a square city with straight streets. A map of a city

HDU 1045——Fire Net——————【最大匹配、构图、邻接矩阵做法】

Fire Net Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 1045 Description Suppose that we have a square city with straight streets. A map of a city is a square board with n rows and n columns, e

HDU 1045 Fire Net(dfs,跟8皇后问题很相似)

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1045 Fire Net Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 14670    Accepted Submission(s): 8861 Problem Description Suppose that we have a squar

HDU - 1045 Fire Net (dfs 或 二分图)

题意:给出一个不会超过4x4的mapmap中有墙,以及空白处.然后你要在空白处放置尽可能多的炮台炮台对向四周发射子弹,即(炮台不能放在同一行或者列除非有强阻挡)思路:首先想到了dfs枚举(就像八皇后一样回溯法),我们尽可能多的在一行一行的放置.关于放置搜索的问题,我们判断是否合法关于二分图匹配(完全没有想出来怎么匹配..)在网上看了别人的题解才懂由于同行或者同列不能多个放置(即每行每列只能放一个除了有墙挡)然后就是建图:将每行每列连续的部分缩成一个点如图:(画的真的丑...) 我们然后这就有连接

HDU 1045 Fire Net (二分匹配)

Fire Net Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Description Suppose that we have a square city with straight streets. A map of a city is a square board with n rows and n columns, each representing a street