bzoj 2055 80人环游地球 上下界费用流

这题像上下界网络流一样,把一条边拆成三条,其中原图中的边权值不变,连向超级源点和汇点的边权值改为0就可以。然后把边合并一下。答案为每条边最小容量*权值+建完图后最小费用流。

#include
#include
#include
#include
#define maxn 405
#define LL long long
using namespace std;
int v[1005];
LL ans=0;
int ss,S,T,inf=1e9;
struct E{
	int to,nxt,cap,d;
}b[100005];
int fst[maxn],cur[maxn],tot=1;
void insert(int f,int t,int c,int d)
{
	b[++tot]=(E){t,fst[f],c,d};fst[f]=tot;
	b[++tot]=(E){f,fst[t],0,-d};fst[t]=tot;
}
struct flow{
	queue Q;
	int dis[maxn],inq[maxn];
	int fro[maxn],froe[maxn];
	bool spfa()
	{
		for(int i=0;i<=T;i++)
			dis[i]=inf;
		dis[S]=0; Q.push(S);
		while(!Q.empty())
		{
			int u=Q.front();Q.pop();inq[u]=0;
			for(int i=fst[u];i;i=b[i].nxt)
			{
				if(!b[i].cap) continue;
				int v=b[i].to;
				if(dis[v]>dis[u]+b[i].d)
				{
					dis[v]=dis[u]+b[i].d;
					fro[v]=u;froe[v]=i;
					if(!inq[v]) Q.push(v),inq[v]=1;
				}
			}
		}
		return dis[T]!=inf;
	}
	int maxflow()
	{
		int ans=0;
		while(spfa())
		{
			int c=0,mn=inf;
			for(int i=T;i!=S;i=fro[i])
				mn=min(mn,b[froe[i]].cap);
			for(int i=T;i!=S;i=fro[i])
			{
				int x=froe[i];
				b[x].cap-=mn;
				b[x^1].cap+=mn;
				ans+=mn*b[x].d;
			}
		}
		return ans;
	}
}Spfa;
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	ss=n*2+1;T=ss+1;
	insert(S,ss,m,0);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&v[i]);
		insert(i,T,v[i],0);
		insert(S,i+n,v[i],0);
		insert(ss,i,m,0);
	}
	int x;
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
		{
			scanf("%d",&x);
			if(x>=0)insert(i+n,j,m,x);
		}
	printf("%d",Spfa.maxflow());
	return 0; 
}

你可能感兴趣的:(===图论===,网络流,===模版===)