[BZOJ1497/Luogu4174][NOI2006]最大獲利
阿新 • • 發佈:2018-12-24
http -c flag return ++ rest bool clas 中轉站
題目鏈接:
BZOJ1497
Luogu4174
最大權閉合子圖應用。
對於每一個中轉站,向匯點連邊,容量為費用的絕對值。
對於每一個用戶,向源點連邊,容量為收益。同時向他需要的中轉站連邊,容量為\(\infty\)。
然後所有用戶的收益-上圖最小割即為所求答案。
為什麽呢?
因為中轉站與匯點連邊若割斷則代表建立中轉站(答案減去費用)
若割斷用戶與源點連邊則代表放棄用戶(答案減去收益)
那麽上網絡流即可。
這裏寫了\(Dinic\)(忘判細節,\(TLE*n\),加了當前弧負優化常數x4)和\(ISAP\)兩種方式。
\(Dinic\quad 6320kb\quad 1012ms(BZOJ)\)
#include <queue> #include <cstdio> #include <cstring> inline int Min(int a,int b){return a<b?a:b;} int n,m,St,Ed; int Head[55555],Next[400005],To[400005],Val[400005],En=1; int Dep[55555],Cur[55555]; inline void Add(int x,int y,int z) { Next[++En]=Head[x],To[Head[x]=En]=y,Val[En]=z; Next[++En]=Head[y],To[Head[y]=En]=x,Val[En]=0; } bool BFS() { std::queue<int> q; memset(Dep,0,sizeof Dep); q.push(St),Dep[St]=1; for(int x,y;!q.empty();q.pop()) for(int i=Head[x=q.front()];i;i=Next[i]) if(Val[i]&&!Dep[y=To[i]]) { Dep[y]=Dep[x]+1,q.push(y); if(y==Ed)return true; } return false; } int Dinic(int x,int Flow) { if(x==Ed)return Flow; int Rest=Flow; for(int i=Head[x],y;i&&Rest;i=Next[i]) if(Val[i]&&Dep[y=To[i]]==Dep[x]+1) { int k=Dinic(y,Min(Val[i],Rest)); if(!k)Dep[y]=0; else Val[i]-=k,Val[i^1]+=k,Rest-=k; } return Flow-Rest; } int main() { scanf("%d%d",&n,&m),St=n+m+1,Ed=St+1; int Ans=0; for(int i=1,p;i<=n;++i) scanf("%d",&p),Add(i,Ed,p); for(int i=1,a,b,c;i<=m;++i) { scanf("%d%d%d",&a,&b,&c); Add(i+n,a,0x3f3f3f3f); Add(i+n,b,0x3f3f3f3f); Add(St,i+n,c),Ans+=c; } int MaxFlow=0,Fs; while(BFS()) while((Fs=Dinic(St,0x3f3f3f3f))) MaxFlow+=Fs; printf("%d\n",Ans-MaxFlow); return 0; }
\(ISAP\quad 6596kb\quad 652ms(BZOJ)\)
#include <queue> #include <cstdio> #include <cstring> inline int Min(int a,int b){return a<b?a:b;} int n,m,St,Ed; int Head[55555],Next[400005],To[400005],Val[400005],En=1; int Dis[55555],Cnt[55555],Cur[55555],Pre[55555]; inline void Add(int x,int y,int z) { Next[++En]=Head[x],To[Head[x]=En]=y,Val[En]=z; Next[++En]=Head[y],To[Head[y]=En]=x,Val[En]=0; } int Augment() { int Res=0x3f3f3f3f; for(int x=Ed;x!=St;x=To[Pre[x]^1])Res=Min(Res,Val[Pre[x]]); for(int x=Ed,i;x!=St;x=To[i^1])Val[i=Pre[x]]-=Res,Val[i^1]+=Res; return Res; } int ISAP() { Cnt[0]=Ed; int Flow=0,x=St; while(Dis[x]<Ed) { if(x==Ed)Flow+=Augment(),x=St; bool Flag=false; for(int i=Cur[x],y;i;i=Next[i]) if(Val[i]&&Dis[x]==Dis[y=To[i]]+1) Flag=true,Pre[y]=Cur[x]=i,x=y,i=0; if(Flag)continue; int Wd=Ed-1; for(int i=Head[x];i;i=Next[i]) if(Val[i])Wd=Min(Wd,Dis[To[i]]); if(!--Cnt[Dis[x]])break; ++Cnt[Dis[x]=Wd+1],Cur[x]=Head[x]; if(x!=St)x=To[Pre[x]^1]; } return Flow; } int main() { scanf("%d%d",&n,&m),St=n+m+1,Ed=St+1; int Ans=0; for(int i=1,p;i<=n;++i) scanf("%d",&p),Add(i,Ed,p); for(int i=1,a,b,c;i<=m;++i) { scanf("%d%d%d",&a,&b,&c); Add(i+n,a,0x3f3f3f3f); Add(i+n,b,0x3f3f3f3f); Add(St,i+n,c),Ans+=c; } int MaxFlow=ISAP(); printf("%d\n",Ans-MaxFlow); return 0; }
[BZOJ1497/Luogu4174][NOI2006]最大獲利