HDOJ:1533-Going Home(最小费用流)

时间:2023-03-08 17:34:31

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1533


解题心得:

  • 第一次写最小费用流的题,去hdoj上找了一个入门级题目,建图比较简单,用了spfa和Dij两种写法。

//spfa
#include <bits/stdc++.h>
using namespace std;
const int maxn = *; struct edge{
int to, cap, dis, rev; edge(int To, int Cap, int Dis, int Rev):
to(To), cap(Cap), dis(Dis), rev(Rev) {}
}; //感觉这里写得超级智障,懒得改了
struct men {
int x,y;
}; struct House {
int x,y;
}; vector <edge> ve[maxn];
vector <men> man;
vector <House> house;
int n, m, S, T;
char maps[maxn][maxn]; void init() {
S = ;
man.clear();
house.clear();
for(int i=;i<maxn;i++)
ve[i].clear();
for(int i=;i<=n;i++)
scanf("%s",maps[i]+);
for(int i=;i<=n;i++) {
for(int j=;j<=m;j++) {
if(maps[i][j] == 'm') {
men now;
now.x = i;
now.y = j;
man.push_back(now);
} else if(maps[i][j] == 'H') {
House temp;
temp.x = i;
temp.y = j;
house.push_back(temp);
}
}
}
T = man.size() + house.size() + ;
} void build_adge(int s, int to, int dis) {
ve[s].push_back(edge(to, , dis, ve[to].size()));
ve[to].push_back(edge(s, , -dis, ve[s].size()-));
} void add_adge() {
for(int i=;i<man.size();i++) {
build_adge(S, i+, );
for(int j=;j<house.size();j++) {
int dis = abs(man[i].x - house[j].x) + abs(man[i].y - house[j].y);
build_adge(i+, man.size()+j+, dis);
}
}
for(int i=;i<house.size();i++) {
build_adge(i++man.size(), T, );
}
} int dist[maxn], preve[maxn], prevv[maxn];
bool vis[maxn];
bool SPFA() {
memset(preve, , sizeof(preve));
memset(vis, , sizeof(vis));
memset(prevv, , sizeof(prevv));
memset(dist, 0x3f, sizeof(dist));
dist[S] = ;
queue <int> qu;
qu.push(S);
while(!qu.empty()) {
int now = qu.front() ;qu.pop();
vis[now] = false;
for(int i=;i<ve[now].size();i++) {
edge &e = ve[now][i];
if(dist[e.to] > dist[now] + e.dis && e.cap > ) {
dist[e.to] = dist[now] + e.dis;
prevv[e.to] = now;
preve[e.to] = i;
if(!vis[e.to]) {
qu.push(e.to);
vis[e.to] = true;
}
}
}
}
return dist[T] != 0x3f3f3f3f;
} int min_cost_flow() {
int ans = ;
while(SPFA()) {
for(int v = T; v!=S ; v =prevv[v]) {
edge &e = ve[prevv[v]][preve[v]];
e.cap -= ;
ve[v][e.rev].cap += ;
ans += e.dis;
}
}
return ans;
} int main() {
while(scanf("%d%d",&n,&m) && n+m) {
init();
add_adge();
printf("%d\n",min_cost_flow());
}
return ;
}

Dij

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
const int maxn = *; struct edge{
int to, cap, dis, rev; edge(int To, int Cap, int Dis, int Rev):
to(To), cap(Cap), dis(Dis), rev(Rev) {}
}; struct men {
int x,y;
}; struct House {
int x,y;
}; vector <edge> ve[maxn];
vector <men> man;
vector <House> house;
int n, m, S, T, h[maxn];
char maps[maxn][maxn]; void init() {
S = ;
man.clear();
house.clear();
memset(h, , sizeof(h));
for(int i=;i<maxn;i++)
ve[i].clear();
for(int i=;i<=n;i++)
scanf("%s",maps[i]+);
for(int i=;i<=n;i++) {
for(int j=;j<=m;j++) {
if(maps[i][j] == 'm') {
men now;
now.x = i;
now.y = j;
man.push_back(now);
} else if(maps[i][j] == 'H') {
House temp;
temp.x = i;
temp.y = j;
house.push_back(temp);
}
}
}
T = man.size() + house.size() + ;
} void build_adge(int s, int to, int dis) {
ve[s].push_back(edge(to, , dis, ve[to].size()));
ve[to].push_back(edge(s, , -dis, ve[s].size()-));
} void add_adge() {
for(int i=;i<man.size();i++) {
build_adge(S, i+, );
for(int j=;j<house.size();j++) {
int dis = abs(man[i].x - house[j].x) + abs(man[i].y - house[j].y);
build_adge(i+, man.size()+j+, dis);
}
}
for(int i=;i<house.size();i++) {
build_adge(i++man.size(), T, );
}
} int dist[maxn], preve[maxn], prevv[maxn];
bool Dij() {
memset(preve, , sizeof(preve));
memset(prevv, , sizeof(prevv));
memset(dist, 0x3f, sizeof(dist));
dist[S] = ;
priority_queue <P, vector<P>, greater<P> > qu;
qu.push(make_pair(,));
while(!qu.empty()) {
P now = qu.top(); qu.pop();
int pos = now.second;
if(dist[pos] < now.first)
continue;
for(int i=;i<ve[pos].size();i++) {
edge &e = ve[pos][i];
if(e.cap > && dist[e.to] > dist[pos] + e.dis + h[pos] - h[e.to]) {
dist[e.to] = dist[pos] + e.dis + h[pos] - h[e.to];
prevv[e.to] = pos;
preve[e.to] = i;
qu.push(make_pair(dist[e.to], e.to));
}
}
}
return dist[T] != 0x3f3f3f3f;
} int min_cost_flow() {
int ans = ;
while(Dij()) {
for(int i=;i<=T;i++)
h[i] += dist[i];
ans += h[T];
for(int v = T; v!=S ; v =prevv[v]) {
edge &e = ve[prevv[v]][preve[v]];
e.cap -= ;
ve[v][e.rev].cap += ;
}
}
return ans;
} int main() {
while(scanf("%d%d",&n,&m) && n+m) {
init();
add_adge();
printf("%d\n",min_cost_flow());
}
return ;
}