SAP最大流。。额额额额额额额额,看不懂的说,把题解贴出来吧,好歹也能算个模版。。
本题可以看成是求A到B的最大流,因为权值在点上,还要进行拆点。
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; #define MAXM 100000 #define MAXN 405 #define INF 2e9 struct eee{ int v,cap,next; eee(){}; eee(int v,int w):v(v),cap(w){} }edge[MAXM]; int first[MAXN]; int d[MAXN];//距离标号 int pre[MAXN]; int numh[MAXN];//GAP数组 int curfirst[MAXN];//各点当前弧 int flow[MAXN]; int e; int n; int m; int S,D; void init(){ memset(first,-1,sizeof(first)); e=0; } void add(int u,int v,int w){ edge[e]=eee(v,w); edge[e].next=first[u]; first[u]=e++; edge[e]=eee(u,0); edge[e].next=first[v]; first[v]=e++; } int sap_maxflow(int st,int en){ int ans=0; for(int i=1;i<=n;i++) curfirst[i]=first[i]; memset(d,0,sizeof(d)); memset(numh,0,sizeof(numh)); numh[0]=n; int i=st; bool ok; int MIN; int aug=INF; while(d[st]<n){ flow[st]=aug; ok=false; for(int j=curfirst[i];j!=-1;j=edge[j].next){ if(edge[j].cap&&d[i]==d[edge[j].v]+1){ ok=true; aug=min(aug,edge[j].cap); curfirst[i]=j; i=edge[j].v; pre[i]=j; if(i==en){ ans+=aug; for(;i!=st;i=edge[pre[i]^1].v){ edge[pre[i]].cap-=aug; edge[pre[i]^1].cap+=aug; } aug=INF; } } } if(ok)continue; MIN=n-1; for(int j=first[i];j!=-1;j=edge[j].next) if(edge[j].cap&&d[edge[j].v]<MIN){ MIN=d[edge[j].v]; curfirst[i]=j; } if(--numh[d[i]]==0)break; d[i]=MIN+1; numh[d[i]]++; if(i!=st){ i=edge[pre[i]^1].v; aug=flow[i]; } } return ans; } int main() { while(scanf("%d%d",&n,&m)==2){ scanf("%d%d",&S,&D); init(); int a,b; add(0,S,INF);//增加超级源点 add(D+n,2*n+1,INF);//增加超级汇点 for(int i=1;i<=n;i++){ scanf("%d",&a); add(i,i+n,a); add(i+n,i,a); } for(int i=0;i<m;i++){ scanf("%d%d",&a,&b); add(a+n,b,INF); add(b+n,a,INF); } S=0;D=2*n+1; n=n*2+2; printf("%d\n",sap_maxflow(S,D)); } return 0; }