• POJ1469 COURSES 二分图匹配 匈牙利算法


    原文链接http://www.cnblogs.com/zhouzhendong/p/8232649.html


    题目传送门 - POJ1469


    题意概括

      在一个大矩阵中,有一些障碍点。

      现在让你用1*2的小矩形覆盖非障碍点,要求不覆盖到障碍点并且不重复覆盖,问是否可以覆盖所有非障碍点。


    题解

      本题几乎是裸题。

      首先注意读入的表示障碍点的二元组(x,y)中y是行,x是列。

      这个毒性深重<差评>

     

      然后考虑算法。读者可以参考笔者的前一篇博客。

      对于相邻的非障碍点我们来回都建边。然后我们给原图按照到某一个点的曼哈顿距离的奇偶性黑白染色,发现黑的只能连向白的,白的也只可以连向黑的。于是这就是一个二分图。

      然后我们跑一炮匈牙利。

      由于连出的边是来回的,所以相当于重复计算了一次,即最大匹配数翻倍了。

      于是就恰好变成了覆盖非障碍点的最大数。直接和障碍点的总数比较即可。

      注意本题用二维数组存图会TLE(我会TLE),改成数组模拟链表就过去了。<差评++>


    代码

    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    const int N=35,K=1100;
    struct Gragh{
    	int cnt,y[K*4],nxt[K*4],fst[K];
    	void clear(){
    		cnt=0;
    		memset(fst,0,sizeof fst);
    	}
    	void add(int a,int b){
    		y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
    	}
    }g;
    int m,n,k,cnt,pl[N][N],tn[N][N],match[K],vis[K];
    bool check(int x,int y){
    	return 1<=x&&x<=m&&1<=y&&y<=n&&!pl[x][y];
    }
    bool Match(int x){
    	for (int i=g.fst[x];i;i=g.nxt[i]){
    		int y=g.y[i];
    		if (!vis[y]){
    			vis[y]=1;
    			if (!match[y]||Match(match[y])){
    				match[y]=x;
    				return 1;
    			}
    		}
    	}
    	return 0;
    }
    int hungary(){
    	int res=0;
    	memset(match,0,sizeof match);
    	for (int i=1;i<=cnt;i++){
    		memset(vis,0,sizeof vis);
    		if (Match(i))
    			res++;
    	}
    	return res;
    }
    int main(){
    	while (~scanf("%d%d%d",&m,&n,&k)){
    		memset(pl,0,sizeof pl);
    		memset(tn,0,sizeof tn);
    		for (int i=1,a,b;i<=k;i++)
    			scanf("%d%d",&b,&a),pl[a][b]=1;
    		cnt=0;
    		for (int i=1;i<=m;i++)
    			for (int j=1;j<=n;j++)
    				if (!pl[i][j])
    					tn[i][j]=++cnt;
    		g.clear();
    		for (int i=1;i<=m;i++)
    			for (int j=1;j<=n;j++){
    				if (pl[i][j])
    					continue;
    				if (check(i,j-1))
    					g.add(tn[i][j],tn[i][j-1]);
    				if (check(i,j+1))
    					g.add(tn[i][j],tn[i][j+1]);
    				if (check(i-1,j))
    					g.add(tn[i][j],tn[i-1][j]);
    				if (check(i+1,j))
    					g.add(tn[i][j],tn[i+1][j]);
    			}
    		puts((hungary()==cnt)?"YES":"NO");
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    kali64位 安装 adb
    ZendStudio在kali下无法启动
    VS2010配置OpenGL开发环境(转)
    OpenGL程序无法启动此应用程序,因为计算机中丢失glut32.dll(转))
    vs2010 出错:error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏(转)
    AnyCAD三维控件(转)
    C# WinForm程序中使用Unity3D控件 (转)
    SharpGL学习笔记(一) 平台构建与Opengl的hello World (转)
    c# Invoke的新用法
    c# 在静态方法里,怎么能得到调用者的类名?
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/POJ1469.html
Copyright © 2020-2023  润新知