zoukankan      html  css  js  c++  java
  • hdu 1045 Fire Net(二分图)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1045

    题目大意为给定一个最大为4*4的棋盘,棋盘可以放置堡垒,处在同一行或者同一列的堡垒可以相互攻击,在棋盘上也有城墙,可以隔离同一行同一列堡垒的相互攻击,“X”表示有城墙,“ . ”表示空地,问该棋盘最多可以放置多少个堡垒?

    此题为二分图匹配问题,但是起初我不知道怎么建图,看题解发现一个规律,同一行同一列的连续空地不能放置两个堡垒,那么同一行同一列的连续空地的交点放置一个堡垒后,该行该列将不能再放置堡垒,这样很容易联想到二分图的性质,那么把连续“行”空地设为l集合,连续的“列”空地设为r集合,也就是说把连续行空地和连续列空地缩点,如果两者在原图中有交点,则可以建边,这样便可以轻易建图了,建图之后跑一下匈牙利算法即可得出答案,其二分图最大匹配数则为该棋盘最多可以放置的堡垒。

    AC代码:

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn = 1001;
    int visit[maxn];//访问数组 
    bool g[maxn][maxn];//建立二分图 
    int match[maxn];//匹配数组 
    int l,r;//l和r两集合 
    
    bool dfs(int u){
    	// i为建图后r集合的节点 ,u为l集合的节点 
    	for(int i = 1;i<=r;i++){//依次遍历集合r 
    		if(g[u][i] && !visit[i]){//如何u和i之间有边,而且i没有被访问过 
    			visit[i] = true;//标记 
    			if(match[i] == -1 || dfs(match[i])){//如果该i没有匹配过则直接匹配u,
    			 //如果匹配过那么尝试dfs寻找增广路 
    				match[i] = u;
    				return true;
    			}
    		}
    	}
    	return false;
    }
    
    int hungary(){
    	int ans = 0;
    	memset(match,-1,sizeof(match));//初始化r匹配的 l
    	for(int i = 1;i<=l;i++){
    		memset(visit,false,sizeof(visit));//初始化l的visit数组,表示都没有访问过 
    		if(dfs(i)){//跑dfs遍历 
    			ans++;//找到一个匹配 
    		}
    	}
    	return ans;
    }
    int main(){
    	int n;
    	vector<int> res;
    	while(~scanf("%d",&n))
    	{
    		memset(g,false,sizeof(g));//初始化图 
    		int markl[5][5];
    		vector<string> s;
    		
    		if(n==0){
    			break;
    		}
    		
    		for(int i = 0;i<n;i++){
    			string t;
    			cin>>t;
    			s.push_back(t); //存string数据 
    		}
    		
    		int step = 0;//step标记点的序号 
    		for(int i = 0;i<n;i++){
    			for(int j = 0;j<n;j++){
    				//如下是缩点操作 
    				if(s[i][j] == '.'){
    					if(j == 0){
    						step++;
    						markl[i][j] = step;
    						continue;
    					}
    					if(s[i][j-1] == 'X'){
    						step++;
    					}
    					markl[i][j] = step;
    				}
    			}
    		}
    		l = step;//记录集合l的数量 
    
    		int markr[5][5];
    		step = 0;
    		for(int j = 0;j<n;j++){
    			for(int i = 0;i<n;i++){
    				if(s[i][j] == '.'){
    					if(i == 0){
    						step++;
    						markr[i][j] = step;
    						continue;
    					}
    					if(s[i-1][j] == 'X'){
    						step++;
    					}
    					markr[i][j] = step;
    				}
    			}
    		}
    		r = step;
    		
    		for(int i = 0;i<n;i++){
    			for(int j = 0;j<n;j++){
    				if(s[i][j] == '.')
    				    g[markl[i][j]][markr[i][j]] = true;//如果缩点后两者有交点,则在邻接矩阵上建边 
    			}
    		}
    		cout<<hungary()<<endl;
    	}
    	return 0;
    }
  • 相关阅读:
    紫色飞猪的研发之旅--07client-go实现进入pod模拟终端登录
    紫色飞猪的研发之旅--06go自定义状态码
    紫色飞猪的研发之旅--05go封装http请求
    紫色飞猪的研发之旅--04client-go客户端
    紫色飞猪的研发之旅--03golang:获取cookie
    支持remote write和exemplar的prometheus服务
    从头编写一个时序数据库
    解析Prometheus PromQL
    老板:把系统从单体架构升级到集群架构!
    小白自制Linux开发板 三. Linux内核与文件系统移植
  • 原文地址:https://www.cnblogs.com/AaronChang/p/12129650.html
Copyright © 2011-2022 走看看