1. 程式人生 > 實用技巧 >【易懂】費用流【SDOI2009】晨跑

【易懂】費用流【SDOI2009】晨跑

【SDOI2009】晨跑

題面

Description

Elaxia最近迷戀上了空手道,他為自己設定了一套健身計劃,比如俯臥撐、仰臥起坐等
等,不過到目前為止,他堅持下來的只有晨跑。
現在給出一張學校附近的地圖,這張地圖中包含N個十字路口和M條街道,Elaxia只能從
一個十字路口跑向另外一個十字路口,街道之間只在十字路口處相交。Elaxia每天從寢室出發
跑到學校,保證寢室編號為1,學校編號為N。
Elaxia的晨跑計劃是按週期(包含若干天)進行的,由於他不喜歡走重複的路線,所以
在一個週期內,每天的晨跑路線都不會相交(在十字路口處),寢室和學校不算十字路
口。Elaxia耐力不太好,他希望在一個週期內跑的路程儘量短,但是又希望訓練週期包含的天
數儘量長。
除了練空手道,Elaxia其他時間都花在了學習和找MM上面,所有他想請你幫忙為他設計
一套滿足他要求的晨跑計劃。

Input

第一行:兩個數N,M。表示十字路口數和街道數。
接下來M行,每行3個數a, b, c,表示路口a和路口b之間有條長度為c的街道(單向)。

Output

兩個數,第一個數為最長週期的天數,第二個數為滿足最長天數的條件下最短的路程長
度。

Sample Input

7 10
1 2 1
1 3 1
2 4 1
3 4 1
4 5 1
4 6 1
2 5 5
3 6 6
5 7 1
6 7 1

Sample Output

2 11

Data Constraint

Hint

資料範圍:
對於30%的資料,N ≤ 20,M ≤ 120。
對於100%的資料,N ≤ 200,M ≤ 20000。

費用流

(假設你已經會了最大流)

費用流,即在最大流的基礎上,選擇權值min值.

我們可以用spfa做最大流(近似ek),權值=單價*距離

程式碼奉上

 1 bool bfs(int s,int t)
 2 {
 3     f(i,1,2*n)
 4     {
 5         dis[i]=flow[i]=inf;
 6     }
 7     int head=0,tail=1;
 8     c[1
]=s;vis[s]=++tot; 9 dis[s]=0;fa[t]=-1; 10 while(head<tail) 11 { 12 int x=c[++head]; 13 vis[x]=0; 14 for(int i=h[x];i;i=e[i].next) 15 { 16 int y=e[i].to; 17 if(e[i].flow&&dis[x]+e[i].dis<dis[y]) 18 { 19 dis[y]=dis[x]+e[i].dis; 20 fa[y]=x; 21 last[y]=i; 22 flow[y]=min(flow[x],(long long)e[i].flow); 23 if(vis[y]!=tot) 24 { 25 vis[y]=tot; 26 c[++tail]=y; 27 } 28 } 29 } 30 } 31 return fa[t]!=-1; 32 } 33 void mcmf(int s,int t) 34 { 35 while(bfs(s,t)) 36 { 37 maxflow+=flow[t]; 38 mincost+=flow[t]*dis[t]; 39 for(int i=fa[t];i!=s;i=fa[i]) 40 { 41 e[last[i]].flow-=flow[t]; 42 e[last[i]^1].flow+=flow[t]; 43 } 44 } 45 }
費用流spfa

本題思路

網路流難在建圖,核心部分copy就好了:

由於本題特殊性,我們採用割點,即x->y+n->n

並且每條邊流量為1/0

如下圖,前者為流量,後者為權值

然後跑一邊費用流即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring> 
 4 #define inf 1000000000
 5 #define S 1
 6 #define T n
 7 #define f(i,a,b) for(register int i=a,x,y,z;i<=b;++i)
 8 #define read(a) scanf("%d",&a)
 9 using namespace std;
10 int n,m,h[1005],cnt=1,fa[1005];
11 long long ans,flow[1005],tot,c[10005],vis[1005],dis[1005],last[1005],maxflow,mincost;
12 struct node
13 {
14     int next,to,flow,dis;
15 }e[100005];
16 void add(int x,int y,int flow,int dis)
17 {
18     e[++cnt].to=y;
19     e[cnt].flow=flow;
20     e[cnt].dis=dis;
21     e[cnt].next=h[x];
22     h[x]=cnt;
23 }
24 bool bfs(int s,int t)
25 {
26     f(i,1,2*n)
27     {
28         dis[i]=flow[i]=inf;
29     }
30     int head=0,tail=1;
31     c[1]=s;vis[s]=++tot;
32     dis[s]=0;fa[t]=-1;
33     while(head<tail)
34     {
35         int x=c[++head];
36         vis[x]=0;
37         for(int i=h[x];i;i=e[i].next)
38         {
39             int y=e[i].to;
40             if(e[i].flow&&dis[x]+e[i].dis<dis[y])
41             {
42                 dis[y]=dis[x]+e[i].dis;
43                 fa[y]=x;
44                 last[y]=i;
45                 flow[y]=min(flow[x],(long long)e[i].flow);
46                 if(vis[y]!=tot)
47                 {
48                     vis[y]=tot;
49                     c[++tail]=y;
50                 }
51             }
52         }
53     }
54     return fa[t]!=-1;
55 }
56 void mcmf(int s,int t)
57 {
58     while(bfs(s,t))
59     {
60         maxflow+=flow[t];
61         mincost+=flow[t]*dis[t];
62         for(int i=fa[t];i!=s;i=fa[i])
63         {
64             e[last[i]].flow-=flow[t];
65             e[last[i]^1].flow+=flow[t];
66         }
67     }
68 }
69 int main()
70 {
71     read(n);read(m);
72     f(i,1,m)
73     {
74         read(x);
75         read(y);
76         read(z);
77         add(x,y+n,1,z);
78         add(y+n,x,0,-z);
79     }
80     f(i,1,n)
81     {
82         add(i+n,i,1,0);
83         add(i,i+n,0,0);
84     }
85     mcmf(S,T);
86     printf("%lld %lld",maxflow,mincost);
87 }
【SDOI2009】晨跑

END·鎮樓圖