【 UVALive - 2197】Paint the Roads(上下界费用流)

Description

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


Sample Output
6
4
28
-1

 

 

【题意】

    有n个点,m条边的有向图,选一些边使得这些边组成若干无公共边的回路(回路不经过重复的点),使得每个点恰好在k个回路上,求满足条件的最小边权和。

 

【分析】

 普通的就拆边,加费用跑费用流判满流。对于新加的约束——每个点必须经过k遍,就把一个点拆成两个点,建上下界流量都为k,一个点只连入边,一个点只连出边即可。

 

代码如下:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 110
  9 #define Maxm 110000
 10 #define INF 0xfffffff
 11 
 12 struct node
 13 {
 14     int x,y,f,c,o,next;
 15 }t[Maxm];int len;
 16 
 17 int st,ed,sum;
 18 int dis[Maxn],pre[Maxn],flow[Maxn],first[Maxn];
 19 bool inq[Maxn];
 20 
 21 int mymin(int x,int y) {return x<y?x:y;}
 22 
 23 void ins(int x,int y,int f,int c)
 24 {
 25     if(f==0) return ;
 26     if(x==st) sum+=f;
 27     t[++len].x=x;t[len].y=y;t[len].f=f;t[len].c=c;
 28     t[len].next=first[x];first[x]=len;t[len].o=len+1;
 29     t[++len].x=y;t[len].y=x;t[len].f=0;t[len].c=-c;
 30     t[len].next=first[y];first[y]=len;t[len].o=len-1;
 31 }
 32 
 33 void make_edge(int x,int y,int k1,int k2,int c)
 34 {
 35     ins(st,y,k2,c);
 36     ins(x,ed,k2,0);
 37     ins(y,x,k2-k1,-c);
 38 }
 39 
 40 queue<int > q;
 41 bool bfs()
 42 {
 43     while(!q.empty()) q.pop();
 44     memset(pre,-1,sizeof(pre));
 45     memset(inq,0,sizeof(inq));
 46     memset(dis,63,sizeof(dis));
 47     pre[st]=0;flow[st]=INF;inq[st]=1;
 48     dis[st]=0;q.push(st);
 49     while(!q.empty())
 50     {
 51         int x=q.front(),y,i;
 52         for(i=first[x];i;i=t[i].next) if(t[i].f>0)
 53         {
 54             y=t[i].y;
 55             if(dis[y]>dis[x]+t[i].c)
 56             {
 57                 pre[y]=i;
 58                 dis[y]=dis[x]+t[i].c;
 59                 flow[y]=mymin(t[i].f,flow[x]);
 60                 if(!inq[y]) {q.push(y);inq[y]=1;}
 61             }
 62         }
 63         q.pop();inq[x]=0;
 64     }
 65     if(pre[ed]==-1) return 0;
 66     return flow[ed];
 67 }
 68 
 69 void max_flow()
 70 {
 71     int ans=0,a,h=0;
 72     while(a=bfs())
 73     {
 74         int now=ed;ans+=a*dis[ed];
 75         while(now!=st)
 76         {
 77             t[pre[now]].f-=a;
 78             t[t[pre[now]].o].f+=a;
 79             now=t[pre[now]].x;
 80         }
 81         h+=a;
 82     }
 83     if(sum!=h) printf("-1\n");
 84     else printf("%d\n",ans);
 85 }
 86 
 87 
 88 int main()
 89 {
 90     int T;
 91     scanf("%d",&T);
 92     while(T--)
 93     {
 94         int n,m,k;
 95         scanf("%d%d%d",&n,&m,&k);
 96         memset(first,0,sizeof(first));
 97         len=0;sum=0;
 98         st=2*n+1;ed=st+1;
 99         for(int i=1;i<=m;i++)
100         {
101             int x,y,c;
102             scanf("%d%d%d",&x,&y,&c);
103             x++;y++;
104             make_edge(x+n,y,0,1,c);
105         }
106         for(int i=1;i<=n;i++) make_edge(i,i+n,k,k,0);
107         max_flow();
108     }
109     return 0;
110 }
[LA2197]

 

2016-06-10 14:59:16

 

转载于:https://www.cnblogs.com/Konjakmoyu/p/5573672.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值