您的位置:首页 > 大数据 > 人工智能

uva 12092 - Paint the Roads(最小费用最大流)

2013-03-25 21:13 435 查看
In a country there are n cities connected by m one way roads. You can paint any of these roads. To paint a road it costs d unit of money where d is the length of that road. Your task is to paint some of the roads so that the painted roads can be partitioned
into some disjoint cycles such that every vertex appears in exactly k of these disjoint cycles. But you have to minimize the costs of painting these roads.
Input
First line of the input contains T the number of test case. Then following lines contains T Test cases.

Each case starts with a line containing 3 integers n (1 ≤ n ≤ 40), m (1 ≤ m ≤ 2000) and k (1 ≤ k and 1≤k*n≤100). Next m lines contain description of m roads. Each line contains three integers f, t (0 ≤ f, t <n and f ≠ t) and d (0 ≤ d < 100). That means there
is a road of d length from city f to city t. You can assume that there will be at most one road in one direction between two cities.

Output

For each test case output contains 1 integer denoting the minimum unit of money needed to paint roads. In the case it is impossible to paint the roads maintaining the constraints output -1.

Sample Input Output for Sample Input

4



4 8 1

0 1 1

1 0 2

2 3 1

3 2 2

0 2 5

2 0 6

1 3 5

3 1 6



4 8 1

0 1 1

1 0 10

2 3 10

3 2 1

0 2 10

2 0 1

1 3 1

3 1 10



4 8 2

0 1 1

1 0 2

2 3 1

3 2 2

0 2 5

2 0 6

1 3 5

3 1 6



3 4 1

0 1 5

1 0 6

0 2 7

2 0 8


6

4

28

-1



Problem setter: Abdullah al Mahmud, Special Thanks: Derek Kisman



还记得在匹配中做过的那道吗?同样的给一个带权有向图,找若干个圈,使得每个节点恰好属于一个圈。

这道题题意解析后其实就是使每个节点恰好属于k个圈。

那道题我们拆点后用最优匹配可以做,因为只要求每个点入度与出度为1,而这里要k,简单的最优匹配显然是不能满足了,

所以要用网络流的特性,加上流量的限制后就可以解决这个所谓的多重匹配问题了。

源点和汇点连的边容量为k,二分图中的边容量为1.

最后判断如果最大流量为n*k,则有解,否则无解



#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn = 202 + 10;
const int INF = 1000000000;

struct Edge {
  int from, to, cap, flow, cost;
};

struct MCMF {
  int n, m, s, t;
  vector<Edge> edges;
  vector<int> G[maxn];
  int inq[maxn];         // 是否在队列中
  int d[maxn];           // Bellman-Ford
  int p[maxn];           // 上一条弧
  int a[maxn];           // 可改进量

  void init(int n) {
    this->n = n;
    for(int i = 0; i < n; i++) G[i].clear();
    edges.clear();
  }

  void AddEdge(int from, int to, int cap, int cost) {
    edges.push_back((Edge){from, to, cap, 0, cost});
    edges.push_back((Edge){to, from, 0, 0, -cost});
    m = edges.size();
    G[from].push_back(m-2);
    G[to].push_back(m-1);
  }

  bool BellmanFord(int s, int t, int &flow,int &cost) {
    for(int i = 0; i < n; i++) d[i] = INF;
    memset(inq, 0, sizeof(inq));
    d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;

    queue<int> Q;
    Q.push(s);
    while(!Q.empty()) {
      int u = Q.front(); Q.pop();
      inq[u] = 0;
      for(int i = 0; i < G[u].size(); i++) {
        Edge& e = edges[G[u][i]];
        if(e.cap > e.flow && d[e.to] > d[u] + e.cost) {
          d[e.to] = d[u] + e.cost;
          p[e.to] = G[u][i];
          a[e.to] = min(a[u], e.cap - e.flow);
          if(!inq[e.to]) { Q.push(e.to); inq[e.to] = 1; }
        }
      }
    }
    if(d[t] == INF) return false;//s-t不连通,失败退出
    flow += a[t];
    //printf("d=%d a=%d\n",d[t],a[t]);
    cost += d[t] * a[t];
    int u = t;
    while(u != s) {
      edges[p[u]].flow += a[t];
      edges[p[u]^1].flow -= a[t];
      u = edges[p[u]].from;
    }
    return true;
  }

  // 需要保证初始网络中没有负权圈
  int Mincost(int& can,int s, int t) {
    int flow = 0,cost = 0;
    while(BellmanFord(s, t,flow, cost));
    can = flow;
    return cost;
  }

};

MCMF g;

int main(){
    int t,n,m,k;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&k);
        g.init(2*n+2);
        int sorce = 2*n,sink = 2*n+1;
        for(int i = 0;i < n;i++){
            g.AddEdge(sorce,i,k,0);
            g.AddEdge(i+n,sink,k,0);
        }
        for(int i = 0;i < m;i++){
            int from,to,dis;
            scanf("%d%d%d",&from,&to,&dis);
            g.AddEdge(from,to+n,1,dis);
        }
        int can;
        int ans = g.Mincost(can,sorce,sink);
        if(can == n*k)  printf("%d\n",ans);
        else    printf("-1\n");
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: