POJ - 2195 (二分最小权匹配 && 最小费用最大流)
作者:互联网
题目连接
题意:
图上,N个小矮人,N个房子,每个单位时间内
每个小矮人都能水平或者垂直移动一个单位步长到相邻的点。
每次移动消费1块钱,直到他进入房屋,每个房子只能容纳一个小矮人
问支付最低的金额。将这N个小矮人送入这N个不同的房间
数据范围:
1 s
N M < 100
N * M的矩阵, H是房子。m是人
思路:
为每个小矮人找到房子,
1)求最小权下的二分匹配
2)费用流:最小费用最大流
建图:源点 - 人 流量1, 费用0
人-房子 流量1,费用曼哈顿距离
房子-汇点 流量1,费用0
跑个费用流
最小权二分匹配AC:
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;
const int maxn = 205;
const int INF = 0x3f3f3f3f;
vector < pair<int, int> > G[maxn * 2];
bool vis_X[maxn], vis_Y[maxn];
int ex_X[maxn], ex_Y[maxn];
int Match[maxn];
int Slack[maxn];
int CntPeo = 1, CntHome = 1;
struct node{
int x, y;
}Peo[maxn],Home[maxn];
void init(){
CntPeo = 1;
CntHome = 1;
}
bool Dfs(int x){
vis_X[x] = 1;
int v, c;
for (int i = 0; i < G[x].size(); ++i) {
v = G[x][i].first;
c = G[x][i].second;
if (vis_Y[v]) continue;
int Tmp = ex_X[x] + ex_Y[v] - c;
if (Tmp != 0) {
Slack[v] = min (Slack[v], Tmp);
} else {
vis_Y[v] = 1;
if (Match[v] == -1 || Dfs(Match[v])) {
Match[v] = x;
//cout << v << " " << Match[v] << " ---" << c <<endl;
return true;
}
}
}
return false;
}
int KM(){
memset(Match, -1, sizeof(Match));
memset(ex_Y, 0, sizeof(ex_Y));
for (int i = 1; i < CntPeo; ++i) {
for(int j = 0; j < G[i].size(); ++j) {
ex_X[i] = max (ex_X[i], G[i][j].second);
}
}
for(int i = 1; i < CntPeo; ++i){
memset(Slack, INF, sizeof(Slack));
while(1){
memset(vis_X, 0, sizeof(vis_X));
memset(vis_Y, 0, sizeof(vis_Y));
if (Dfs(i)) break;
int Tmp = INF;
for(int j = 1; j < CntHome; ++j){
if(vis_Y[j] == 0)
Tmp = min(Tmp, Slack[j]);
}
if(Tmp == INF) return -1;
for (int j = 1; j < CntPeo; ++j) {
if (vis_X[j]) ex_X[j] -= Tmp;
}
for (int j = 1; j < CntHome; ++j) {
if (vis_Y[j]) ex_Y[j] += Tmp;
else Slack[j] -= Tmp;
}
}
}
int Ans = 0;
for(int i = 1; i < CntHome; ++i){
if(Match[i] != -1){
for(int j = 0; j < G[Match[i]].size(); ++j){
if (G[Match[i]][j].first == i){
Ans += G[Match[i]][j].second;
//cout << Match[i] << " " << i << " ---" << G[Match[i]][j].second << endl;
}
}
}
}
return -Ans;
}
int Distance(node a, node b) {
return fabs(a.x - b.x) + fabs(a.y - b.y);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
char ch;
int N, M;
while(cin >> N >> M && N && M){
init();
for (int i = 1; i <= N; ++i) {
for(int j = 1; j <= M; ++j) {
cin >> ch;
if(ch == 'H'){
Peo[CntPeo].x = i;
Peo[CntPeo++].y = j;
}
if(ch == 'm'){
Home[CntHome].x = i;
Home[CntHome++].y = j;
}
}
}
for(int i = 1; i < CntPeo; ++i) {
G[i].clear();
}
for(int i = 1; i < CntPeo; ++i) {
for(int j = 1; j < CntHome; ++j) {
int c = Distance(Peo[i], Home[j]);
G[i].push_back(make_pair (j, -c) );
//cout << i << " " << j << "="<< c << endl;
}
}
cout << KM() << endl;
}
return 0;
}
费用流AC:
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
int N, M;
char G[150][150];
struct Point{
int x, y;
};
const int maxn = 505;
const int inf = 0x3f3f3f3f;
int path[maxn], dis[maxn], head[maxn], vis[maxn], cnt;
void init() {
cnt = 0;
memset(head, -1, sizeof(head));
}
struct node{
int v, flow, cost, nex;
}edge[maxn * maxn];
void addEdge(int u, int v, int flow, int cost) {
edge[cnt] = {v, flow, cost, head[u]};
head[u] = cnt++;
edge[cnt] = {u, 0, -cost, head[v]};
head[v] = cnt++;
}
int Spfa(int s, int t) {
memset(vis, 0, sizeof(vis));
memset(dis, inf, sizeof(dis));
memset(path, -1, sizeof(path));
queue<int> que;
que.push(s);
dis[s] = 0;
vis[s] = 1;
while(!que.empty()) {
int u = que.front();
que.pop();
vis[u] = 0;
for(int i = head[u]; i != -1; i = edge[i].nex){
int v = edge[i].v;
int flow = edge[i].flow;
int cost = edge[i].cost;
if (flow > 0 && dis[v] > dis[u] + cost) {
dis[v] = dis[u] + cost;
path[v] = i;
if(vis[v]) continue;
vis[v] = 1;
que.push(v);
}
}
}
return dis[t] != inf;
}
int MCMF(int s, int t, int &cost) {
int maxflow = 0;
while(Spfa(s, t)) {
int flow = inf;
for (int i = path[t]; i != -1; i = path[edge[i ^ 1].v]) {
flow = min(flow, edge[i].flow);
}
for (int i = path[t]; i != -1; i = path[edge[i^1].v]) {
edge[i].flow -= flow;
edge[i^1].flow += flow;
cost += flow * edge[i].cost;
}
maxflow += flow;
}
return maxflow;
}
int Distance(Point a, Point b) {
return fabs(a.x - b.x) + fabs(a.y - b.y);
}
int main () {
Point People[maxn], House[maxn];
while(~scanf("%d%d", &N, &M) && N + M){
init();
for(int i = 0; i < N; ++i) {
scanf("%s", G[i]);
}
int CntP = 1;
int CntH = 1;
for (int i = 0; i < N; ++i) {
for (int j = 0; j < M; ++j) {
if(G[i][j] == 'm'){
People[CntP].x = i;
People[CntP].y = j;
CntP++;
}
else if(G[i][j] == 'H') {
House[CntH].x = i;
House[CntH].y = j;
CntH++;
}
}
}
for (int i = 1; i < CntP; ++i) {
for (int j = 1; j < CntH; ++j) {
int dis = Distance(People[i], House[j]);
addEdge(i, j + 100, 1, dis);
}
}
for(int i = 1; i < CntP; ++i) {
addEdge(0, i, 1, 0);
}
for(int j = 1; j < CntH; ++j) {
addEdge(j + 100, 201, 1, 0);
}
int Cost = 0;
int Ans = MCMF(0, 201, Cost);
printf("%d\n", Cost);
}
return 0;
}
标签:int,flow,最小,++,edge,maxn,2195,POJ,include 来源: https://blog.csdn.net/Harington/article/details/101100490