第一次做最小费用流的问题,之前一直是盲点。
从这道题来看,我对最小费用最大流的理解是,在最大流约束的条件下,每次寻找可行路都找费用最小的那一条,做若干次最短路,直到最后没有增广路。
这道题点的总数可达到202,第一次交题的时候没注意,导致RE
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#define lson node<<1,l,l+r>>1
#define rson node<<1|1,(l+r>>1)+1,r
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int _maxNodes = 1e5+10;
struct Node{
int x, y;
Node(){}
Node(int u, int v){
x = u; y = v;
}
};
Node man[210], house[210];
int n,m;
char graph[210][210];
int num_m, num_h;
int source, sink;
int cost[210][210], d[210][210];
int parent[210];
bool vis[210];
int mincost[210];
int ans;
void init(){
for (int i = 0; i < n; i++){
scanf("%s", graph[i]);
}
num_m = num_h = 0;
for (int i = 0; i < n; i++){
for (int j = 0; j < m; j++){
if (graph[i][j] == 'H'){
house[++num_h] = Node(i, j);
}
else if (graph[i][j] == 'm'){
man[++num_m] = Node(i, j);
}
}
}
source = 0; sink = num_m + num_h + 1;
memset(cost,0,sizeof cost);
memset(d,0,sizeof d);
for (int i = 1; i <= num_m; i++){
d[source][i] = 1;
}
for (int i = 1; i <= num_m; i++){
for (int j = 1; j <= num_h; j++){
d[i][num_m+j] = 1;
cost[i][num_m+j] = abs(man[i].x - house[j].x) + abs(man[i].y - house[j].y);
cost[num_m+j][i] = -cost[i][num_m+j];
}
}
for (int i = 1; i <= num_h; i++){
d[num_m+i][sink] = 1;
}
}
void SPFA(){
queue<int> que;
int v, i;
memset(vis,false,sizeof(vis));
memset(parent,-1,sizeof (parent));
for (i = source; i <= sink; i++) mincost[i] = INF;
que.push(source);
mincost[source] = 0;
vis[source] = true;
while (!que.empty()){
v = que.front(); que.pop();
vis[v] = false;
for (i = source; i <= sink; i++){
if (d[v][i] && mincost[v] + cost[v][i] < mincost[i]){
mincost[i] = mincost[v] + cost[v][i];
parent[i] = v;
if (!vis[i]){
que.push(i);
vis[i] = true;
}
}
}
}
}
void solve(){
int v;
ans = 0;
while (1){
SPFA();
if (parent[sink] == -1) break;
v = sink;
while (parent[v] != -1){
d[parent[v]][v] -= 1;
d[v][parent[v]] += 1;
v = parent[v];
}
ans += mincost[sink];
}
printf("%d\n",ans);
}
int main(){
while (scanf("%d %d",&n, &m) == 2){
if (n == 0 && m == 0) break;
init();
solve();
}
return 0;
}