题目大意:给定一张拓扑图,每条边有边权,每次只能从第一个点出发沿着拓扑图走一条路径,求遍历所有边所需要的最小边权和
有下界有源汇的最小费用流 裸的。。。
建图如下:
对于每一条边权为z的边x->y:
从S到y连一条费用为z,流量为1的边 代表这条边至少走一次
从x到y连一条费用为z,流量为INF的边 代表这条边除了至少走的一次之外还可以随便走
对于每个点x:
从x到T连一条费用为0,流量为x的出度的边
从x到1连一条费用为0,流量为INF的边,代替原图上的源和汇
直接跑费用流就能过- - 裸EK跑了6s
看RANK1这时间MS不是费用流?
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 310 #define S 0 #define T (n+1) #define INF 0x3f3f3f3f using namespace std; int n,m,ans; namespace Min_Cost_Max_Flow{ struct abcd{ int to,flow,cost,next; }table[1001001]; int head[M],tot=1; void Add(int x,int y,int f,int c) { table[++tot].to=y; table[tot].flow=f; table[tot].cost=c; table[tot].next=head[x]; head[x]=tot; } void Link(int x,int y,int f,int c) { Add(x,y,f,c); Add(y,x,0,-c); } bool Edmonds_Karp() { static int q[65540],f[M],cost[M],from[M]; static unsigned short r,h; static bool v[M]; int i; memset(cost,0x3f,sizeof cost); cost[S]=0;f[S]=INF;f[T]=0;q[++r]=S; while(r!=h) { int x=q[++h];v[x]=0; for(i=head[x];i;i=table[i].next) if(table[i].flow&&cost[x]+table[i].cost<cost[table[i].to]) { cost[table[i].to]=cost[x]+table[i].cost; f[table[i].to]=min(f[x],table[i].flow); from[table[i].to]=i; if(!v[table[i].to]) v[table[i].to]=1,q[++r]=table[i].to; } } if(!f[T]) return false; ans+=f[T]*cost[T]; for(i=from[T];i;i=from[table[i^1].to]) table[i].flow-=f[T],table[i^1].flow+=f[T]; return true; } } int main() { //freopen("3876.in","r",stdin); using namespace Min_Cost_Max_Flow; int i,j,y,z; cin>>n; for(i=1;i<=n;i++) { scanf("%d",&m); for(j=1;j<=m;j++) { scanf("%d%d",&y,&z); Link(i,y,INF,z); Link(S,y,1,z); } Link(i,T,m,0); if(i!=1) Link(i,1,INF,0); } while( Edmonds_Karp() ); cout<<ans<<endl; }