设为首页 加入收藏

TOP

HDU 1045 Fire Net 二分图Bipartite题解
2015-07-20 17:50:44 来源: 作者: 【 】 浏览:1
Tags: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 
  
   
#include 
   
     #include 
    
      #include 
     
       #include 
      
        #include 
       
         #include 
        
          #include 
         
           #include 
          
            #include 
           
             #include 
             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<
  
   


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇poj 1580 String Matching(比较字.. 下一篇UVa 348 Optimal Array Multiplic..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

Shell 基本运算符 -
Shell 函数 | 菜鸟教
Linux 常用命令集合
socket 编程如何实现
Python创建简易的Soc