【CodeChef】Annual Parade -最小费用最大流&无向图最小链覆盖

版权声明:欢迎转载(请附带原链接)ヾ(๑╹◡╹)ノ" https://blog.csdn.net/corsica6/article/details/84313265

传送门:Annual Parade


题解

求链覆盖所有点的最小花费,考虑拆点跑最小费用最大流。

1 0 5 10^5 次关于 C C 的询问说明费用流实际上和 C C 的关系不大。
先考虑如何抛开 C C 回答单次询问。

考虑拆点:将 i i 拆成 i , i i,i'
源点 S S -> i i 连一条流量为 1 1 ,费用为 0 0 的边。
i i ->汇点 T T 连一条流量为 1 1 ,费用为 0 0 的边。
每条路径 ( x , y , v ) (x,y,v) 连一条 x > y x->y' 流量为 1 1 ,费用为 v v 的边。
i i' -> i i 连一条流量为 + +\infty ,费用为 0 0 的边(多次经过一个点)。

观察每次一条新的增广路(费用为 c o s t cost )的贡献:连接了两条不连通的路径,使得原花费 C -C ;连成了环,也使得原花费 C -C

初始化费用为 n × C n\times C (没有路径),每一条新的增广路的贡献为 c o s t c cost-c 。那么花费最小的方案就是选择所有 c o s t < c cost<c 的增广路。

所以先 F l o y d Floyd 跑一遍任意两点之间最短路,跑一遍最小费用最大流,依次记录每条增广路的花费。最后每次询问二分回答即可。


代码

#include<bits/stdc++.h>
using namespace std;
const int N=510,M=4e5+10;
const int inf=0x3f3f3f3f;

int n,m,K,S,T,f[255][255],vs[N],tim,lim;
int head[N],cur[N],to[M],nxt[M],w[M],c[M],tot=1;
bool inq[N];int dis[N],prf,prc,flw[N],cst[N];

vector<int>dg;

inline void lk(int u,int v,int vv,int cc)
{
	to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=vv;c[tot]=cc;
	to[++tot]=u;nxt[tot]=head[v];head[v]=tot;w[tot]=0;c[tot]=-cc;
}

char cp,OS[100];
inline void rd(int &x)
{
	cp=getchar();x=0;
	for(;!isdigit(cp);cp=getchar());
	for(;isdigit(cp);cp=getchar()) x=(x<<3)+(x<<1)+(cp^48);
}

inline void ot(int x)
{
	int re=0;
	for(;(!re)||(x);x/=10) OS[++re]='0'+x%10;
	for(;re;--re) putchar(OS[re]);
	putchar('\n');
}

deque<int>que;
inline bool spfa()
{
	int i,j,x;
	memset(dis,0x3f,lim);dis[T]=0;inq[T]=true;que.push_back(T);
	for(;que.size();){
		x=que.front();que.pop_front();
		for(i=head[x];i;i=nxt[i]){
			j=to[i];if((!w[i^1])||(dis[j]<=dis[x]-c[i])) continue;
			dis[j]=dis[x]-c[i];if(inq[j]) continue;
			if(que.empty() || dis[j]<=dis[que.front()]) que.push_front(j);
			else que.push_back(j);inq[j]=true;
		}
		inq[x]=false;
	}
	return dis[S]<inf;
}

int dfs(int x,int f,int cot)
{
	vs[x]=tim;
	if(x==T){
		dg.push_back(cot);
		int sz=dg.size();
		prf+=f;flw[sz]=prf;
		prc+=f*cot;cst[sz]=prc;
		return f;
	}
	int j,res,ss=0;
	for(int &i=cur[x];i;i=nxt[i]){
		j=to[i];if((!w[i])||(vs[j]==tim)||(dis[j]!=dis[x]-c[i])) continue;
		res=dfs(j,min(f-ss,w[i]),cot+c[i]);if(!res) continue;
		w[i]-=res;w[i^1]+=res;ss+=res;
		if(ss==f) return ss;
	}
	if(!ss) dis[x]=-1;
	return ss;
}

int main(){
	int i,j,k,x,y,z;
	memset(f,0x3f,sizeof(f));
	rd(n);rd(m);rd(K);
	for(i=1;i<=n;++i) f[i][i]=0;
	for(i=1;i<=m;++i){
		rd(x);rd(y);rd(z);
		f[x][y]=min(f[x][y],z);
	}
	for(k=1;k<=n;++k)
	 for(i=1;i<=n;++i)
	  for(j=1;j<=n;++j)
	    f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
	S=(n<<1)+1;T=S+1;lim=sizeof(int)*(T+2);
	for(i=1;i<=n;++i) lk(S,i,1,0),lk(i+n,T,1,0);
	for(i=1;i<=n;++i)
	 for(j=1;j<=n;++j) if((i!=j)&&(f[i][j]<inf))
	   lk(i,j+n,1,f[i][j]);
	for(;spfa();){
		for(vs[T]=tim;vs[T]==tim;){
			tim++;memcpy(cur,head,lim);dfs(S,inf,0);
		}
	}
	for(;K;--K){
		rd(z);x=lower_bound(dg.begin(),dg.end(),z)-dg.begin();
		ot((n-flw[x])*z+cst[x]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/84313265
今日推荐