生活随笔
收集整理的這篇文章主要介紹了
[ZJOI2010]网络扩容[网络流24题]
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
[ZJOI2010]網(wǎng)絡(luò)擴(kuò)容[網(wǎng)絡(luò)流24題]
題意:
給定一張有向圖,每條邊都有一個(gè)容量 c 和一個(gè)擴(kuò)容費(fèi)用 w。這里擴(kuò)容費(fèi)用是指將容量擴(kuò)大 1 所需的費(fèi)用。求:
在不擴(kuò)容的情況下,1 到 n 的最大流;
將 1 到 n 的最大流增加 k 所需的最小擴(kuò)容費(fèi)用
題解:
第一問(wèn)好說(shuō)就是跑最大流,關(guān)鍵是第二問(wèn)怎么想
兩個(gè)方法:
其實(shí)本質(zhì)也是一個(gè),我們可以將擴(kuò)容的費(fèi)用轉(zhuǎn)化為增加一點(diǎn)流量,花費(fèi)W的費(fèi)用,因?yàn)槲覀円屬M(fèi)用盡可能低,所以問(wèn)題就成了最小費(fèi)用流的模型
如何建圖呢?
我們可以在第一問(wèn)的基礎(chǔ)上繼續(xù)建圖,也可以重新建圖(個(gè)人傾向第一種)
如果是第一種,我們?cè)谂芡曜畲罅骱?#xff0c;利用殘余網(wǎng)絡(luò)繼續(xù)建圖,(第一問(wèn)建圖中每條弧的費(fèi)用都是0的),我們?cè)僭诘趇條弧的兩端之間建一條弧,弧的容量為INF,費(fèi)用是cost[i],這樣保證費(fèi)用是最低的
但是題目要求是增加k,怎么能控制這個(gè)量呢?我們只需要在建立一個(gè)超級(jí)源點(diǎn)或者超級(jí)匯點(diǎn)(建立一個(gè)即可),連接S(T),容量為K,費(fèi)用為0,也就是我們限制流入量或者流出量最多為K即可
代碼:
調(diào)了半天,終于寫出來(lái)了。。。。
注意cnt要從1開始
因?yàn)?和1是一對(duì)相反邊,2和3是一對(duì)。。。
#include<bits/stdc++.h>
#define inf 0x3f3f3f
#define mem(x,a) memset(x,a,sizeof(x))
typedef long long ll
;
using namespace std
;
inline int read(){int s
=0,w
=1;char ch
=getchar();while(ch
<'0'||ch
>'9'){if(ch
=='-')w
=-1;ch
=getchar();}while(ch
>='0'&&ch
<='9') s
=s
*10+ch
-'0',ch
=getchar();return s
*w
;
}
int n
,m
,k
;
int S
,T
,cnt
=1;
const int maxn
=1e6+9;
struct node
{int u
,v
,w
,cost
,next
;
}edge
[maxn
];
int head
[maxn
],dis
[maxn
],uu
[maxn
],vv
[maxn
],ww
[maxn
];inline void add_edge(int u
,int v
,int w
,int dis
)
{edge
[++cnt
].next
=head
[u
];edge
[cnt
].u
=u
;edge
[cnt
].v
=v
;edge
[cnt
].w
=w
;edge
[cnt
].cost
=dis
;head
[u
]=cnt
;
}
void add(int u
,int v
,int w
,int dis
)
{add_edge(u
,v
,w
,dis
);add_edge(v
,u
,0,-dis
);
}
int level
[maxn
];
bool makelevel(int s
,int t
)
{queue
<int>q
;q
.push(s
);mem(level
,0);level
[s
]=1;while(!q
.empty()){int u
=q
.front();q
.pop();
for(int i
=head
[u
];i
;i
=edge
[i
].next
){int v
=edge
[i
].v
;int w
=edge
[i
].w
;if(level
[v
]==0&&w
!=0){level
[v
]=level
[u
]+1;q
.push(v
);}}}return level
[t
];
}
int dfs(int u
,int flow
,int t
)
{if(u
==t
)return flow
;int sum
=0;for(int i
=head
[u
];i
;i
=edge
[i
].next
){int v
=edge
[i
].v
;int w
=edge
[i
].w
;if(level
[v
]==level
[u
]+1&&w
!=0){int tmp
=dfs(v
,min(flow
-sum
,w
),t
);edge
[i
].w
-=tmp
;edge
[i
^1].w
+=tmp
;sum
+=tmp
;if(sum
==flow
)return sum
;}}return sum
;
}
int dinic()
{int ans
=0;while(makelevel(S
,T
)){ans
+=dfs(S
,inf
,T
);}return ans
;
}
int fa
[maxn
],vis
[maxn
],xb
[maxn
],flow
[maxn
];
inline bool spfa(int s
,int t
)
{memset(dis
,0x3f,sizeof(dis
));memset(vis
,0,sizeof(vis
));queue
<int> q
;while(!q
.empty())q
.pop();mem(fa
,-1);vis
[s
]=1;dis
[s
]=0;fa
[s
]=0;flow
[s
]=inf
;q
.push(s
);while(!q
.empty()){int u
=q
.front();q
.pop();vis
[u
]=0;for(int i
=head
[u
];i
;i
=edge
[i
].next
){int v
=edge
[i
].v
;if(edge
[i
].w
>0&&dis
[v
]>dis
[u
]+edge
[i
].cost
){dis
[v
]=dis
[u
]+edge
[i
].cost
;fa
[v
]=u
;xb
[v
]=i
;flow
[v
]=min(flow
[u
],edge
[i
].w
);if(!vis
[v
]){vis
[v
]=1,q
.push(v
);}}}}return fa
[t
]!=-1;
}
inline int mcmf(int s
,int t
)
{int sum
=0;while(spfa(s
,t
)){int k
=t
;while(k
!=s
){edge
[xb
[k
]].w
-=flow
[t
];edge
[xb
[k
]^1].w
+=flow
[t
];k
=fa
[k
];}
sum
+=flow
[t
]*dis
[t
];}return sum
;
}
int main()
{cin
>>n
>>m
>>k
;S
=1;T
=n
;for(int i
=1;i
<=m
;i
++){int u
,v
,w
;cin
>>uu
[i
]>>vv
[i
]>>ww
[i
]>>dis
[i
];add(uu
[i
],vv
[i
],ww
[i
],0);}
cout
<<dinic()<<" ";for(int i
=1;i
<=m
;i
++){add(uu
[i
],vv
[i
],inf
,dis
[i
]);}add(0,1,k
,0);cout
<<mcmf(0,n
);}
總結(jié)
以上是生活随笔為你收集整理的[ZJOI2010]网络扩容[网络流24题]的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。