您的位置:首页 > 其它

poj 2446 Chessboard

2015-05-20 09:07 387 查看
题意:在m*n的矩阵中,有一些孔,问除了那些孔以外的网格,能不能两两连接在一起。

分析:其实把每个网格看成一个点,就是点之间的匹配,但如果看成普通图的最大匹配话就做不了,于是把点分成黑白两色,坐标相加和为偶数的为白色,否则为黑色,这样就把这个问题转化成了二分图最大匹配,跑一遍匈牙利算法,求出最大匹配然后判断 最大匹配*2 +k 是不是等于 n*m即可。

以下附上代码:

#include <algorithm>
#include <iostream>
#include <sstream>
#include <fstream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cctype>
#include <cmath>
#include <stack>
#include <queue>
#include <list>
#include <map>
#include <set>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

const int maxn = 1025;

int g[33][33];
int m,n,k;
int cx[maxn],cy[maxn];
bool vis[maxn];
vector<int> adlist[maxn];

void input()
{
int x,y;
int i,j;
for(i = 0; i <= n*m; i++)
adlist[i].clear();
for(i = 0; i <= m; i++){
for(j = 0; j <= n; j++){
g[i][j] = 0;
}
}

for(i = 0; i < k; i++) {
scanf("%d%d",&x,&y);
g[y][x] = 1;
}
for(i = 1; i <= m; i++){
for(j = 1; j <= n; j++){
if(!g[i][j] && (i+j) % 2 == 0){
//up
if(i-1 >= 1 && !g[i-1][j]) adlist[(i-1)*n + j].push_back((i-2)*n + j);
//down
if(i+1 <= m && !g[i+1][j]) adlist[(i-1)*n + j].push_back(i*n + j);
//left
if(j-1 >= 1 && !g[i][j-1]) adlist[(i-1)*n + j].push_back((i-1)*n + j-1);
//right
if(j+1 <= n && !g[i][j+1]) adlist[(i-1)*n + j].push_back((i-1)*n + j+1);
}
}
}

}

int path(int u)
{
int i;
int v;
for(i = 0; i < adlist[u].size(); i++){
v = adlist[u][i];
if(!vis[v]){
vis[v] = 1;
if(cy[v] == -1 || path(cy[v])){
cx[u] = v;
cy[v] = u;
return 1;
}
}
}
return 0;
}

int maxMatch()
{
int res = 0;
int i;
fill(cx,cx+n*m+1,-1);
fill(cy,cy+n*m+1,-1);
for(i = 1; i <= n*m; i++){
if(cx[i] == -1){
fill(vis,vis+n*m+1,0);
res += path(i);
}
}
return res;
}

bool solve()
{
return maxMatch() * 2 + k == n * m;
}

int main()
{
while(scanf("%d%d%d",&m,&n,&k) != EOF){
input();
puts(solve() ? "YES" : "NO");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: