题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1533
解题心得:
- 第一次写最小费用流的题,去hdoj上找了一个入门级题目,建图比较简单,用了spfa和Dij两种写法。
//spfa
#include <bits/stdc++.h> using namespace std; const int maxn = 110*110; 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 = 0; man.clear(); house.clear(); for(int i=0;i<maxn;i++) ve[i].clear(); for(int i=1;i<=n;i++) scanf("%s",maps[i]+1); for(int i=1;i<=n;i++) { for(int j=1;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() + 1; } void build_adge(int s, int to, int dis) { ve[s].push_back(edge(to, 1, dis, ve[to].size())); ve[to].push_back(edge(s, 0, -dis, ve[s].size()-1)); } void add_adge() { for(int i=0;i<man.size();i++) { build_adge(S, i+1, 0); for(int j=0;j<house.size();j++) { int dis = abs(man[i].x - house[j].x) + abs(man[i].y - house[j].y); build_adge(i+1, man.size()+j+1, dis); } } for(int i=0;i<house.size();i++) { build_adge(i+1+man.size(), T, 0); } } int dist[maxn], preve[maxn], prevv[maxn]; bool vis[maxn]; bool SPFA() { memset(preve, 0, sizeof(preve)); memset(vis, 0, sizeof(vis)); memset(prevv, 0, sizeof(prevv)); memset(dist, 0x3f, sizeof(dist)); dist[S] = 0; queue <int> qu; qu.push(S); while(!qu.empty()) { int now = qu.front() ;qu.pop(); vis[now] = false; for(int i=0;i<ve[now].size();i++) { edge &e = ve[now][i]; if(dist[e.to] > dist[now] + e.dis && e.cap > 0) { 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 = 0; while(SPFA()) { for(int v = T; v!=S ; v =prevv[v]) { edge &e = ve[prevv[v]][preve[v]]; e.cap -= 1; ve[v][e.rev].cap += 1; 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 0; }
Dij
#include <bits/stdc++.h> using namespace std; typedef pair<int,int> P; const int maxn = 110*110; 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 = 0; man.clear(); house.clear(); memset(h, 0, sizeof(h)); for(int i=0;i<maxn;i++) ve[i].clear(); for(int i=1;i<=n;i++) scanf("%s",maps[i]+1); for(int i=1;i<=n;i++) { for(int j=1;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() + 1; } void build_adge(int s, int to, int dis) { ve[s].push_back(edge(to, 1, dis, ve[to].size())); ve[to].push_back(edge(s, 0, -dis, ve[s].size()-1)); } void add_adge() { for(int i=0;i<man.size();i++) { build_adge(S, i+1, 0); for(int j=0;j<house.size();j++) { int dis = abs(man[i].x - house[j].x) + abs(man[i].y - house[j].y); build_adge(i+1, man.size()+j+1, dis); } } for(int i=0;i<house.size();i++) { build_adge(i+1+man.size(), T, 0); } } int dist[maxn], preve[maxn], prevv[maxn]; bool Dij() { memset(preve, 0, sizeof(preve)); memset(prevv, 0, sizeof(prevv)); memset(dist, 0x3f, sizeof(dist)); dist[S] = 0; priority_queue <P, vector<P>, greater<P> > qu; qu.push(make_pair(0,0)); while(!qu.empty()) { P now = qu.top(); qu.pop(); int pos = now.second; if(dist[pos] < now.first) continue; for(int i=0;i<ve[pos].size();i++) { edge &e = ve[pos][i]; if(e.cap > 0 && 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 = 0; while(Dij()) { for(int i=0;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 -= 1; ve[v][e.rev].cap += 1; } } return ans; } int main() { while(scanf("%d%d",&n,&m) && n+m) { init(); add_adge(); printf("%d\n",min_cost_flow()); } return 0; }