HDU 2448 Mining Station on the Sea

题意:有N艘船和N个港口,M个station。现在N艘船分别处在一些station上。有K条边连接站,有P条边连接港口和站。现在这N艘船都要回到港口,且每个港口只能容纳一艘船。问使这N艘船回到港口行程之和的最小值是多少。

比较明显的求最小权匹配,用KM。做最短路的时候要注意如果船已经回到港口了,就不能再跑出去了,所以做floyd闭包或其他最短路的时候,松弛的时候不能用港口去松弛一个点对。然后得到各个船所在位置到各个港口的最短路后,把边权赋成负的船到港口的最短路值,然后跑KM就可以了。

  1 #include <cstdio>
  2 #include <vector>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define maxn 105
  6 #define INF 1<<30
  7 using namespace std;
  8 
  9 struct KM{
 10     vector<int> G[maxn];
 11     int W[maxn][maxn],n;
 12     int Lx[maxn],Ly[maxn];
 13     int left[maxn];
 14     bool S[maxn],T[maxn];
 15 
 16     void init(int n)
 17     {
 18         this->n = n;
 19         for(int i = 0;i < n;i++)    G[i].clear();
 20         memset(W,0,sizeof(W));
 21     }
 22 
 23     void add_edge(int u,int v,int w)
 24     {
 25         G[u].push_back(v);
 26         W[u][v] = w;
 27     }
 28 
 29     bool match(int i)
 30     {
 31         S[i] = true;
 32         for(int k = 0;k < G[i].size();k++)
 33         {
 34             int j = G[i][k];
 35             if(Lx[i] + Ly[j] == W[i][j] && !T[j])
 36             {
 37                 T[j] = true;
 38                 if(left[j] == -1 || match(left[j]))
 39                 {
 40                     left[j] = i;
 41                     return true;
 42                 }
 43             }
 44         }
 45         return false;
 46     }
 47     void update()
 48     {
 49         int a = INF;
 50         for(int i = 0;i < n;i++)    if(S[i])
 51             for(int k = 0;k < G[i].size();k++)
 52             {
 53                 int j = G[i][k];    if(!T[j])
 54                 a = min(a,Lx[i] + Ly[j] - W[i][j]);
 55             }
 56         for(int i = 0;i < n;i++)
 57         {
 58             if(S[i])    Lx[i] -= a;
 59             if(T[i])    Ly[i] += a;
 60         }
 61     }
 62 
 63     void solve()
 64     {
 65         for(int i = 0;i < n;i++)
 66         {
 67             Lx[i] = *max_element(W[i],W[i]+n);
 68             left[i] = -1;
 69             Ly[i] = 0;
 70         }
 71         for(int i = 0;i < n;i++)
 72         {
 73             while(1)
 74             {
 75                 for(int j = 0;j < n;j++)    S[j] = T[j] = 0;
 76                 if(match(i))    break;
 77                 else            update();
 78             }
 79         }
 80     }
 81 };
 82 KM solver;
 83 int d[310][310];
 84 int pos[105];
 85 
 86 int main(){
 87     int n,m,k,p;
 88     while(scanf("%d%d%d%d",&n,&m,&k,&p) != EOF){
 89         for(int i = 1;i <= n;i++)   scanf("%d",&pos[i]);
 90 
 91         for(int i = 1;i <= m+n;i++)
 92         for(int j = 1;j <= m+n;j++){
 93             if(i != j)  d[i][j] = -1;
 94             else    d[i][j] = 0;
 95         }
 96 
 97         for(int i = 0;i < k;i++){
 98             int a,b,c;
 99             scanf("%d%d%d",&a,&b,&c);
100             d[a][b] = d[b][a] = d[a][b] == -1 ? c : min(c,d[a][b]);
101         }
102 
103         for(int i = 0;i < p;i++){
104             int a,b,c;
105             scanf("%d%d%d",&a,&b,&c);
106             d[m+a][b] = d[b][m+a] = d[m+a][b] == -1 ? c : min(c,d[m+a][b]);
107         }
108 
109         for(int k = 1;k <= m;k++)
110         for(int i = 1;i <= m+n;i++) if(d[i][k] != -1)
111         for(int j = 1;j <= m+n;j++) if(d[k][j] != -1 && (d[i][j] == -1 || d[i][j] > d[i][k] + d[k][j]))
112         d[i][j] = d[i][k] + d[k][j];
113 
114         solver.init(n);
115 
116         for(int i = 1;i <= n;i++)
117         for(int j = 1;j <= n;j++)
118         if(d[pos[i]][m+j] != -1)
119         solver.add_edge(i-1,j-1,-d[pos[i]][m+j]);
120 
121         solver.solve();
122 
123         int ans = 0;
124         for(int i = 0;i < n;i++)
125         ans -= solver.W[solver.left[i]][i];
126         printf("%d
",ans);
127     }
128     return 0;
129 }
View Code
原文地址:https://www.cnblogs.com/zhexipinnong/p/3409154.html