程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> poj Going Home

poj Going Home

編輯:C++入門知識

poj Going Home


Going Home

題目:

給出一個N*M的圖,圖上的m表示人,H表示房子,每座房子只能有一個人,要求你所有人到房子中總步數最少。m個數與H個數一樣多。

算法分析:

這個題目還是比較裸的。可以想到先求出每個人到每座房子的距離。然後求出最小花費,這個好像就是最小費用流吧?一開始用了KM寫完後,發現。。。。哪裡不對啊?後來才覺悟,原來題目是求解最小花費,KM是最大匹配下最大權值。。。。。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef pair 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 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 cost;
map 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  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,greater

> 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; }


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved