原文链接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; }