您的位置:首页 > 其它

uva 1045(二分图最大权匹配)

2014-02-25 20:56 525 查看
题意:n*n的棋盘上有n枚棋子。现在要让你以最小的步数把棋盘分隔开(可以是横竖着的五个一排, 也可以是两个对角线)。问你最小步数

思路:首先枚举各个最终状态起始状态与最终状态建边权值为花费的负数,然后求最大权匹配去一下最大值。最后答案再取相反数。

代码如下:

/**************************************************
* Author     : xiaohao Z
* Blog     : http://www.cnblogs.com/shu-xiaohao/ * Last modified : 2014-02-25 19:54
* Filename     : uva_1045.cpp
* Description     :
* ************************************************/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define MP(a, b) make_pair(a, b)
#define PB(a) push_back(a)

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<unsigned int,unsigned int> puu;
typedef pair<int, double> pid;
typedef pair<ll, int> pli;
typedef pair<int, ll> pil;

const int INF = 0x3f3f3f3f;
const double eps = 1E-6;
const int LEN = 101;
int nx, ny, Map[LEN][LEN], n;
int link[LEN], lx[LEN], ly[LEN], slack[LEN], visx[LEN], visy[LEN];
struct P{int x, y;}p[LEN];

//template from kuangbin
int dfs(int x){
visx[x] = 1;
for(int y=0; y<ny; y++){
if(visy[y]) continue;
int tmp = lx[x] + ly[y] - Map[x][y];
if(!tmp){
visy[y] = 1;
if(link[y] < 0 || dfs(link[y])){
link[y] = x;
return true;
}
}else if(slack[y] > tmp) slack[y] = tmp;
}
return false;
}

int KM(){
memset(link, -1, sizeof link);
memset(ly, 0, sizeof ly);
for(int i=0; i<nx; i++){
lx[i] = -INF;
for(int j=0; j<ny; j++)
if(Map[i][j] > lx[i]) lx[i] = Map[i][j];
}
for(int x=0; x<nx; x++){
for(int i=0; i<ny; i++) slack[i] = INF;
while(true){
memset(visx, 0, sizeof visx);
memset(visy, 0, sizeof visy);
if(dfs(x)) break;
int d = INF;
for(int i=0; i<ny; i++)
if(!visy[i] && d > slack[i]) d = slack[i];
for(int i=0; i<nx; i++) if(visx[i]) lx[i] -= d;
for(int i=0; i<ny; i++){
if(visy[i]) ly[i] += d;
else slack[i] -= d;
}
}
}
int ret = 0;
for(int i=0; i<ny; i++)
if(link[i] != -1) ret += Map[link[i]][i];
return ret;
}

inline int dis(int a, int b, int c, int d){return abs(a-c) + abs(b-d);}

int main()
{
//    freopen("in.txt", "r", stdin);

int kase = 1;
while(scanf("%d", &n)!=EOF && n){
nx = ny = n;
for(int i=0; i<n; i++){
scanf("%d%d", &p[i].x, &p[i].y);
p[i].x--;p[i].y--;
}
int ans = -INF;
//row
for(int i=0; i<n; i++){
memset(Map, 0x3f, sizeof Map);
for(int j=0; j<n; j++)
for(int k=0; k<n; k++){
Map[j][k] = -dis(p[j].x, p[j].y, i, k);
}
ans = max(ans, KM());
}
//col
for(int i=0; i<n; i++){
memset(Map, 0x3f, sizeof Map);
for(int j=0; j<n; j++)
for(int k=0; k<n; k++)
Map[j][k] = -dis(p[j].x, p[j].y, k, i);
ans = max(ans, KM());
}
//
memset(Map, 0x3f, sizeof Map);
for(int i=0; i<n; i++)
for(int j=0; j<n; j++){
Map[i][j] = -dis(p[i].x, p[i].y, j, j);
}
ans = max(ans, KM());
memset(Map, 0x3f, sizeof Map);
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
Map[i][j] = -dis(p[i].x, p[i].y, j, n-j-1);
ans = max(ans, KM());
ans = -ans;
printf("Board %d: %d moves required.\n\n", kase++, ans);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: