【uva 1658】Admiral(图论--网络流 最小费用最大流)

题意:有个N个点M个边的有向加权图,求1~N的两条不相交路径(除了起点和终点外没有公共点),使得权和最小。

解法:不相交?也就是一个点只能经过一次,也就是我后面博文会讲的“结点容量问题”。(呃不,写完这博文几天后的今天,我负责任地 m(._.)m 告诉大家,我不会写这博文了......我的时间不多了......          m(_ _;;m 大家可以看蓝书。)常用方法就是拆点法,把一个点拆成两个点,中间连一条容量为1、费用为0的边。于是求1到 n 的流量为2的最小费用流就可以了。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<queue>
 6 using namespace std;
 7 
 8 const int N=1010,M=10010,NN=2010,MM=22000,D=110,INF=(int)1e9;
 9 int n,m,len;
10 int last[NN],d[NN],vis[NN],flow[NN];
11 int pre[NN],id[NN];
12 struct edge{int x,y,fl,c,next;}e[MM];
13 queue<int> q;
14 
15 int mmin(int x,int y) {return x<y?x:y;}
16 void ins(int x,int y,int fl,int c)
17 {
18     e[++len].x=x,e[len].y=y,e[len].fl=fl,e[len].c=c;
19     e[len].next=last[x],last[x]=len;
20     e[++len].x=y,e[len].y=x,e[len].fl=0,e[len].c=-c;
21     e[len].next=last[y],last[y]=len;
22 }
23 bool spfa(int st,int ed)
24 {
25     while (!q.empty()) q.pop();
26     memset(d,63,sizeof(d));//>1e9
27     memset(vis,0,sizeof(vis));
28     memset(pre,0,sizeof(pre));
29     q.push(st);
30     d[st]=0,vis[st]=1,flow[st]=INF;
31     while (!q.empty())
32     {
33       int x=q.front(); q.pop(); 
34       vis[x]=0;//spfa
35       for (int i=last[x];i;i=e[i].next)
36       {
37         int y=e[i].y;
38         if (d[x]+e[i].c<d[y] && e[i].fl)
39         {
40           d[y]=d[x]+e[i].c;
41           flow[y]=mmin(flow[x],e[i].fl);
42           pre[y]=x, id[y]=i;
43           if (!vis[y]) q.push(y),vis[y]=1;
44         }
45       }
46     }
47     return pre[ed];
48 }
49 int Max_flow(int st,int ed)
50 {
51     int sum=0;
52     while (spfa(st,ed))
53     {
54       sum+=flow[ed]*d[ed];
55       for (int i=ed;i!=st;i=pre[i])
56       {
57         e[id[i]].fl-=flow[ed];
58         e[id[i]^1].fl+=flow[ed];
59       }
60     }
61     return sum;
62 }
63 int main()
64 {
65     while (scanf("%d%d",&n,&m)!=EOF)
66     {
67       int x,y,z; len=1;
68       memset(last,0,sizeof(last));
69       for (int i=2;i<n;i++) ins(i,n+i-1,1,0);
70       ins(n,2*n-1,2,0);
71 //拆点就是真的拆点不能ins(i,i...)  n+1~2n-2
72       for (int i=1;i<=m;i++)
73       {
74         scanf("%d%d%d",&x,&y,&z);
75         if (x!=1) x=n+x-1;//只有1没有拆多一个点
76         ins(x,y,1,z);
77       }
78       //for (int i=2;i<=len;i++)
79       //  printf("%d %d %d %d %d\n",e[i].x,e[i].y,e[i].fl,e[i].c,e[i].next);
80       int ans=Max_flow(1,2*n-1);
81       printf("%d\n",ans);
82     }
83     return 0;
84 }

 

转载于:https://www.cnblogs.com/konjak/p/6049656.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值