题目大意
给定一个无向图,一个物体从图中A点要运动到B点(A,B之间至少经过一点),现在需要派人拦截该物体。派人到每个点需要不同的费用,请问如何安排保证拦截该物体使得派人的总费用最少。 如果有多种方案满足要求,则输出字典序最小的一组解。
求无向图最小割集,在满足代价最小的情况下,输出字典序最小的一组解。
数据范围
(2≤ N ≤200)N为点数
(1≤ M ≤20000)M为边数
样例输入
5 6
5 3
2
4
8
3
10
1 5
1 2
2 4
4 5
2 3
3 4
样例输出
1 4
代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
int n,S,T,cnt,N,vl[505],h[505],dis[505],GAP[505];
struct node{int to,next,v,pair;}e[100005],ee[100005],eee[100005];
void AddEdge(int x,int y,int v,int pair){e[cnt]=(node){y,h[x],v,pair};h[x]=cnt;}
void AddEdge(int x,int y,int v){AddEdge(x,y,v,++cnt+1);AddEdge(y,x,0,++cnt-1);}
int SAP(int x,int Maxflow){//最大流
if(x==T)return Maxflow;
int tmp=Maxflow;
for(int p=h[x];p;p=e[p].next){
int y=e[p].to;
int flow=min(tmp,e[p].v);
if(flow&&dis[x]==dis[y]+1){
int ret=SAP(y,flow);
tmp-=ret;
e[p].v-=ret;
e[e[p].pair].v+=ret;
if(!tmp||dis[S]==N)return Maxflow-tmp;
}
}
if(--GAP[dis[x]]==0)dis[S]=N;
else GAP[++dis[x]]++;
return Maxflow-tmp;
}
int SAP(){
memset(dis,0,sizeof(dis));
memset(GAP,0,sizeof(GAP));
GAP[0]=N;
int Ans=0;
while(dis[S]<N)Ans+=SAP(S,1<<30);
return Ans;
}
int main(){
n=Getint();
int m=Getint();
S=Getint()*2-1,T=Getint()*2;
N=2*n;
for(int i=1;i<=n;i++)AddEdge(i*2-1,i*2,Getint());//拆点建边
for(int i=1;i<=m;i++){
int x=Getint(),y=Getint();
AddEdge(x*2,y*2-1,1<<30);
AddEdge(y*2,x*2-1,1<<30);
}
memcpy(ee,e,sizeof(e));//ee,eee均为e的备份
int Ans=SAP();
memcpy(eee,e,sizeof(e));
for(int i=1;i<=2*n;i+=2){//从小到大枚举每个点是满足条件,从而保证字典序
if(e[i].v)continue;
int t=e[i+1].v;
memcpy(e,ee,sizeof(ee));
e[i].v=e[i+1].v=0;
int ret=SAP();
if(Ans-ret==t){//若减少的量刚好等于这个点的流量,则满足条件,输出
cout<<(i+1)/2<<" ";
Ans=ret;
ee[i].v=0;
memcpy(eee,e,sizeof(e));
}else memcpy(e,eee,sizeof(ee));
}
return 0;
}