Going Home
题目:
给出一个N*M的图,图上的m表示人,H表示房子,每座房子只能有一个人,要求你所有人到房子中总步数最少。m个数与H个数一样多。
算法分析:
这个题目还是比较裸的。可以想到先求出每个人到每座房子的距离。然后求出最小花费,这个好像就是最小费用流吧?一开始用了KM写完后,发现。。。。哪里不对啊?后来才觉悟,原来题目是求解最小花费,KM是最大匹配下最大权值。。。。。
#include <iostream> #include <algorithm> #include <vector> #include <queue> #include <map> #include <cstdio> #include <cstring> using namespace std; typedef pair<int,int> P; const int INF = 1 << 20; const int MAXN = 400 + 10; ///////////////////////////// //最小费用 struct Edge{ int to,cap,cost,rev; Edge(){}; Edge(int _to,int _cap,int _cost,int _rev) :to(_to),cap(_cap),cost(_cost),rev(_rev){}; }; vector<Edge> G[MAXN]; int V; int h[MAXN]; int dist[MAXN]; int prevv[MAXN],preve[MAXN]; int src,sink; /////////////////////////////////////// //查找距离 struct Point{ int x,y,dis; Point(){}; Point(int _x,int _y,int _dis) :x(_x),y(_y),dis(_dis){}; }; vector<Point> cost; map<int,int> mp; int N,M,cnt1,cnt2; char str[MAXN][MAXN]; int dirx[5] = {-1,1,0,0}; int diry[5] = {0,0,-1,1}; int W[MAXN][MAXN],ans[MAXN]; int slack,Lx[MAXN],Ly[MAXN],Link[MAXN]; bool S[MAXN],T[MAXN]; //////////////////////////////////// bool check(int x,int y){ if(x >= 0&& x < N&&y >=0 && y < M) return true; return false; } void bfs(int s,int e){ bool vst[MAXN][MAXN]; memset(vst,0,sizeof(vst)); queue <Point> que; que.push(Point(s,e,0)); vst[s][e] = 1; while(!que.empty()){ Point pv = que.front(); que.pop(); for(int i = 0;i < 4;++i){ Point tmp; tmp.x = pv.x + dirx[i]; tmp.y = pv.y + diry[i]; tmp.dis = pv.dis + 1; if(check(tmp.x,tmp.y)&&!vst[tmp.x][tmp.y]){ vst[tmp.x][tmp.y] = 1; if(str[tmp.x][tmp.y] == 'H'){ int num = tmp.x * N + tmp.y; if(mp.count(num) == 0){ mp[num] = ++cnt2; } cost.push_back(Point(cnt1,mp[num],tmp.dis)); } que.push(tmp); } } } } // //bool Match(int i){ // S[i] = true; // for(int j = 1;j <= cnt2;++j)if(!T[j]){ // int tmp = Lx[i] + Ly[j] - W[i][j]; // if(tmp == 0){ // T[j] = true; // if(Link[j] == -1||Match(Link[j])){ // Link[j] = i; // return true; // } // } // else if(tmp < slack) // slack = tmp; // } // return false; //} // //void update(int d){ // for(int i = 1;i <= cnt1;++i) // if(S[i]) Lx[i] -= d; // for(int i = 1;i <= cnt2;++i) // if(T[i]) Ly[i] += d; //} // //bool EK(){ // for(int i = 1;i <= cnt1;++i){ // Link[i] = -1; // Lx[i] = Ly[i] = 0; // for(int j = 1;j <= cnt2;++j) // Lx[i] = max(Lx[i],W[i][j]); // } // // slack = INF; // // for(int i = 1;i <= cnt1;++i){ // for(;;){ // memset(S,false,sizeof(S)); // memset(T,false,sizeof(T)); // if(Match(i)) // break; // // if(slack == INF) // return false; // update(slack); // } // // } // return true; //} // //int getAns(){ // int sum = 0; // for(int j = 1;j <= cnt2;++j){ // if(Link[j] != -1) // sum += W[Link[j]][j]; // } // return sum; //} void addEdge(int from,int to,int cap,int cost){ G[from].push_back(Edge(to,cap,cost,G[to].size())); G[to].push_back(Edge(from,0,-cost,G[from].size() - 1)); } int min_cost_flow(int s,int t,int f){ int res = 0; V = sink + 1; fill(h,h + V,0); while(f > 0){ priority_queue<P,vector<P>,greater<P> > que; fill(dist,dist + V,INF); dist[s] = 0; que.push(P(0,s)); while(!que.empty()){ P p = que.top(); que.pop(); int v = p.second; if(dist[v] < p.first) continue; for(int i = 0;i < (int)G[v].size();++i){ Edge& e = G[v][i]; int tmp = dist[v] + e.cost + h[v] - h[e.to]; if(e.cap > 0 && dist[e.to] > tmp){ dist[e.to] = tmp; prevv[e.to] = v; preve[e.to] = i; que.push(P(dist[e.to],e.to)); } } } if(dist[t] == INF){ return -1; } for(int v = 1;v < V;++v) h[v] += dist[v]; int dd = f; for(int v = t;v != s ;v = prevv[v]){ dd = min(dd,G[prevv[v]][preve[v]].cap); } f -= dd; res += dd * h[t]; for(int v = t;v != s;v = prevv[v]){ Edge& e = G[prevv[v]][preve[v]]; e.cap -= dd; G[v][e.rev].cap += dd; } } return res; } void init(){ for(int i = 0;i <= sink;++i) G[i].clear(); } void solve(){ cnt1 = 0; cnt2 = 0; mp.clear(); cost.clear(); //查找距离 for(int i = 0;i < N;++i){ for(int j = 0;j < M;++j){ if(str[i][j] == 'm'){ cnt1++; bfs(i,j); } } } Point tmp; for(int i = 0;i < (int)cost.size();++i){ tmp = cost[i]; W[tmp.x][tmp.y] = tmp.dis; } //建图 V = cnt1 + cnt2; src = V + 1; sink = src + 1; init(); for(int i = 1;i <= cnt1;++i){ //m for(int j = 1;j <= cnt2;++j){ //H addEdge(i,j + cnt1,1,W[i][j]); } } for(int i = 1;i <= cnt1;++i){ addEdge(src,i,1,0); } for(int i = 1;i <= cnt2;++i){ //!!!!!!!! 变点的时候一定要注意啊! addEdge(cnt1 + i,sink,1,0); } int res = min_cost_flow(src,sink,cnt1); printf("%d\n",res); } int main() { //freopen("Input.txt","r",stdin); while(scanf("%d%d",&N,&M),(N||M)){ for(int i = 0;i < N;++i){ scanf("%s",str[i]); } solve(); } return 0; }
时间: 2024-10-23 14:26:32