1. 程式人生 > >BZOJ1497 最大獲利

BZOJ1497 最大獲利

false PE con eof UC emc 代碼 div bzoj

題目鏈接:https://cn.vjudge.net/problem/HYSBZ-1497

知識點:  最小割

解題思路:

  將中轉站和用戶群都視為點,再建立一個源點和一個匯點。

  從源點到每個中轉站建一條邊,容量為該中轉站的建立成本,割掉這條邊就代表建立了這個中轉站,損失了該中轉站的建立成本(即該邊的容量)。

  從每一個用戶群到匯點建一條邊,容量為該用戶群的獲益,割掉這條邊就代表不滿足這個用戶群,損失了該用戶群的收益(即該邊容量)。

  對於該用戶群所使用的中轉站,連一條邊到該用戶群,容量為 \(INF\),這樣就保證了:若要滿足該用戶群(即保留該用戶群到匯點的邊),則其所使用的中轉站與源點之間的邊必須割(代表該用戶群所使用的中轉站都必須建立);反之則割掉該用戶群到匯點的邊(即不滿足該用戶群)。

  答案即為所有用戶群的總收益減去從源點到匯點的網絡流的最小割。

  最後介紹一下最大流最小割定理:在一個網絡流中,能夠從源點到達匯點的最大流量等於如果從網絡中移除就能夠導致網絡流中斷的邊的集合的最小容量和。即在任何網絡中,最大流的值等於最小割的容量。

AC代碼:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int MAXN=60000;
const int MAXM=400000;
const int INF=0x3f3f3f3f;
struct Edge{
    int to,nest,cap,flow;
}edge[MAXM];
int head[MAXN],tol; int gap[MAXN],dep[MAXN],cur[MAXN]; void init(){ tol=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int w,int rw=0){ edge[tol].to=v; edge[tol].cap=w; edge[tol].flow=0; edge[tol].nest=head[u]; head[u]=tol++; edge[tol].to=u; edge[tol].cap=rw; edge[tol].flow=0
; edge[tol].nest=head[v]; head[v]=tol++; } int Q[MAXN]; void BFS(int start,int ends){ memset(dep,-1,sizeof(dep)); memset(gap,0,sizeof(gap)); gap[0]=1; int fronts=0,rear=0; dep[ends]=0; Q[rear++]=ends; while(fronts!=rear){ int u=Q[fronts++]; for(int i=head[u];i!=-1;i=edge[i].nest){ int v=edge[i].to; if(dep[v]!=-1) continue; Q[rear++]=v; dep[v]=dep[u]+1; gap[dep[v]]++; } } } int S[MAXN]; int sap(int start,int ends,int N){ BFS(start,ends); memcpy(cur,head,sizeof(head)); int top=0; int u=start; int ans=0; while(dep[start]<N){ if(u==ends){ int Min=INF; int inser; for(int i=0;i<top;i++){ if(Min>edge[S[i]].cap-edge[S[i]].flow){ Min=edge[S[i]].cap-edge[S[i]].flow; inser=i; } } for(int i=0;i<top;i++){ edge[S[i]].flow+=Min; edge[S[i]^1].flow-=Min; } ans+=Min; top=inser; u=edge[S[top]^1].to; continue; } bool flag=false; int v; for(int i=cur[u];i!=-1;i=edge[i].nest){ v=edge[i].to; if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u]){ flag=true; cur[u]=i; break; } } if(flag){ S[top++]=cur[u]; u=v; continue; } int Min=N; for(int i=head[u];i!=-1;i=edge[i].nest){ if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min){ Min=dep[edge[i].to]; cur[u]=i; } } gap[dep[u]]--; if(!gap[dep[u]]) return ans; dep[u]=Min+1; gap[dep[u]]++; if(u!=start) u=edge[S[--top]^1].to; } return ans; } int main(){ int N,M,a,b,c; int s=0,t=MAXN-1; init(); scanf("%d%d",&N,&M); for(int i=1;i<=N;i++){ scanf("%d",&c); addedge(s,i,c); } int sum=0; for(int i=1;i<=M;i++){ scanf("%d%d%d",&a,&b,&c); sum+=c; addedge(a,i+N,INF); addedge(b,i+N,INF); addedge(i+N,t,c); } printf("%d\n",sum-sap(s,t,N+M+2)); return 0; }

BZOJ1497 最大獲利