hdu-1853 Cyclic Tour(最小费用最大流)

Cyclic Tour

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/65535 K (Java/Others)
Total Submission(s): 2376    Accepted Submission(s): 1218


Problem Description
There are N cities in our country, and M one-way roads connecting them. Now Little Tom wants to make several cyclic tours, which satisfy that, each cycle contain at least two cities, and each city belongs to one cycle exactly. Tom wants the total length of all the tours minimum, but he is too lazy to calculate. Can you help him?
 

Input
There are several test cases in the input. You should process to the end of file (EOF).
The first line of each test case contains two integers N (N ≤ 100) and M, indicating the number of cities and the number of roads. The M lines followed, each of them contains three numbers A, B, and C, indicating that there is a road from city A to city B, whose length is C. (1 ≤ A,B ≤ N, A ≠ B, 1 ≤ C ≤ 1000).
 

Output
Output one number for each test case, indicating the minimum length of all the tours. If there are no such tours, output -1. 
 

Sample Input
  
  
6 9 1 2 5 2 3 5 3 1 10 3 4 12 4 1 8 4 6 11 5 4 7 5 6 9 6 5 4 6 5 1 2 1 2 3 1 3 4 1 4 5 1 5 6 1
 

Sample Output
  
  
42 -1
Hint
In the first sample, there are two cycles, (1->2->3->1) and (6->5->4->6) whose length is 20 + 22 = 42.

第一次接触这种题目,看了大佬的题解才知道是网络流(网络流果然强大啊),学习了大佬的拆点方法自己写了下(其实网络流除了拆点就是模板了= =)

题意:有n个点,m条有向边,边的起点,终点,权值分别为u,v,c,问是否能用若干的环覆盖整个图,并且环之间没有交点

题解:最小费用最大流,先建立源点和汇点,标记为s=0和t=2n+1;然后拆点,对于顶点u,拆成u和u+n,将s与u连一条容量为1费用为0的有向边,u+n与t连一条容量为1费用为0的有向边,如果u和v相连,则将u与v+n连一条容量为1费用为c的有向边,这样就完成构图了.①为什么边的容量为1呢?从题目可以知道如果图符合要求,那么每个点的入度和出度一定为1,即容量为1.②为什么这样拆点就可以了?我们这样拆点就可以把点的入"和"出"分开,如果总流量等于n的话,就表示每个点都"入"了一次且"出"了一次,这就保证了所有的点都在这若干个环里面,且环之间没有交点(如果有交点就一定有点的出度或者入度不等于1,那么在①的限制下流量就会小于n)

#include<cstdio>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 205;
struct Edge{
    int v,c,w,nxt;
}edge[maxn*maxn*4];
int head[maxn],tot;
bool vis[maxn];
int d[maxn],pre[maxn];
void add(int u,int v,int c,int w){
    edge[tot].v=v;
    edge[tot].c=c;
    edge[tot].w=w;
    edge[tot].nxt=head[u];
    head[u]=tot++;
}
bool spfa(int s,int t){
    queue<int>q;
    memset(vis,0,sizeof(vis));
    memset(d,0x3f,sizeof(d));
    memset(pre,-1,sizeof(pre));
    q.push(s);
    vis[s]=1;
    d[s]=0;
    while(!q.empty()){
        int u=q.front();q.pop();
        vis[u]=0;
        for(int i=head[u];~i;i=edge[i].nxt){
            int v=edge[i].v;
            if(edge[i].w>0&&d[v]>d[u]+edge[i].c){
                d[v]=d[u]+edge[i].c;
                pre[v]=i;
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }

    return ~pre[t];
}
int MinCostMaxFlow(int s,int t,int &cost){
    int flow=0;
    cost=0;
    while(spfa(s,t)){
        int minFlow=inf;
        for(int i=pre[t];~i;i=pre[edge[i^1].v]){
            minFlow=min(minFlow,edge[i].w);
        }
        for(int i=pre[t];~i;i=pre[edge[i^1].v]){
            edge[i].w-=minFlow;
            edge[i^1].w+=minFlow;
            cost+=edge[i].c*minFlow;
        }
        flow+=minFlow;
    }
    return flow;
}
int main(){
    int n,m;
   // freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m)){
        tot=0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++){
            add(0,i,0,1);
            add(i,0,0,0);

            add(i+n,2*n+1,0,1);
            add(2*n+1,i+n,0,0);
        }

        for(int i=0;i<m;i++){
            int u,v,c;
            scanf("%d%d%d",&u,&v,&c);

            add(u,v+n,c,1);
            add(v+n,u,-c,0);
        }

        int ans=0;
        if(MinCostMaxFlow(0,2*n+1,ans)==n) printf("%d\n",ans);
        else printf("-1\n");
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值