题目大意:给定一张拓扑图,每条边有边权,每次只能从第一个点出发沿着拓扑图走一条路径,求遍历所有边所需要的最小边权和
有下界有源汇的最小费用流 裸的。。。
建图如下:
对于每一条边权为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;
}