[bzoj1797][Ahoi2009]Mincut 最小割
來自FallDream的博客,未經允許,請勿轉載,謝謝qaq
A,B兩個國家正在交戰,其中A國的物資運輸網中有N個中轉站,M條單向道路。設其中第i (1≤i≤M)條道路連接了vi,ui兩個中轉站,那么中轉站vi可以通過該道路到達ui中轉站,如果切斷這條道路,需要代價ci。現在B國想找出一個路徑切斷方案,使中轉站s不能到達中轉站t,并且切斷路徑的代價之和最小。? 小可可一眼就看出,這是一個求最小割的問題。但愛思考的小可可并不局限于此。現在他對每條單向道路提出兩個問題:?? 問題一:是否存在一個最小代價路徑切斷方案,其中該道路被切斷?? 問題二:是否對任何一個最小代價路徑切斷方案,都有該道路被切斷??? 現在請你回答這兩個問題。
n<=4000 m<=60000
題解:先跑一次最小割,然后在殘量網絡上tarjan,用所有沒滿流的邊縮點。
由于是最小割,所以顯然ST不在同一塊
一條邊如果沒有滿流,那么它就不可能被割了。在這基礎上:
一條邊可以被割當且僅當連接的兩個點所屬的塊不同。
一條邊一定被割當且僅當連接的兩個點分別和S,T同塊。
證明我不會,轉一個鏼爺(jcvb)的題解:
<==將每個SCC縮成一個點,得到的新圖就只含有滿流邊了。那么新圖的任一s-t割都對應原圖的某個最小割,從中任取一個把id[u]和id[v]割開的割即可證明。
?< ==:假設將(u,v)的邊權增大,那么殘余網絡中會出現s->u->v->t的通路,從而能繼續增廣,于是最大流流量(也就是最小割容量)會增大。這即說明(u,v)是最小割集中必須出現的邊。
#include<iostream> #include<cstdio> #include<cstring> #define ll long long #define MN 4000 #define INF 2000000000 using namespace std; inline int read() {int x = 0 , f = 1; char ch = getchar();while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();}while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f; }int n,m,S,T,head[MN+5],cnt=1,d[MN+5],c[MN+5],q[MN+5],top,dn=0,dfn[MN+5],low[MN+5],bel[MN+5],cc=0; struct edge{int from,to,next,w;}e[120005];inline void ins(int f,int t,int w) {e[++cnt]=(edge){f,t,head[f],w};head[f]=cnt;e[++cnt]=(edge){t,f,head[t],0};head[t]=cnt; }int dfs(int x,int f) {if(x==T)return f;int used=0;for(int&i=c[x];i;i=e[i].next)if(e[i].w&&d[e[i].to]==d[x]+1){int w=dfs(e[i].to,min(f-used,e[i].w));used+=w;e[i].w-=w;e[i^1].w+=w;if(used==f)return used;}return d[x]=-1,used; }bool bfs() {memset(d,0,sizeof(d));int i,j;for(d[q[top=i=1]=S]=1;i<=top;i++)for(j=c[q[i]]=head[q[i]];j;j=e[j].next)if(e[j].w&&!d[e[j].to])d[q[++top]=e[j].to]=d[q[i]]+1;return d[T]; }void tarjan(int x) {dfn[x]=low[x]=++dn;q[++top]=x;for(int i=head[x];i;i=e[i].next)if(e[i].w){if(!dfn[e[i].to]) tarjan(e[i].to),low[x]=min(low[x],low[e[i].to]);elseif(!bel[e[i].to]) low[x]=min(low[x],dfn[e[i].to]); }if(dfn[x]==low[x])for(++cc;q[top+1]!=x;--top)bel[q[top]]=cc; }int main() {n=read();m=read();S=read();T=read();for(int i=1;i<=m;i++){int u=read(),v=read(),c=read();ins(u,v,c);}while(bfs()) dfs(S,INF); top=0;memset(q,0,sizeof(q));for(int i=1;i<=n;i++)if(!dfn[i]) tarjan(i);for(int i=2;i<=cnt;i+=2)printf("%d %d\n",!e[i].w&&bel[e[i].from]!=bel[e[i].to],bel[e[i].from]==bel[S]&&bel[e[i].to]==bel[T]);return 0; }?
轉載于:https://www.cnblogs.com/FallDream/p/bzoj1797.html
總結
以上是生活随笔為你收集整理的[bzoj1797][Ahoi2009]Mincut 最小割的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Solidworks输出Autocad的
- 下一篇: git的一些常用操作
