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

来源:互联网 发布:淘宝美工设计软件 编辑:程序博客网 时间:2024/05/16 09:06

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 91 2 52 3 53 1 103 4 124 1 84 6 115 4 75 6 96 5 46 51 2 12 3 13 4 14 5 15 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
原创粉丝点击