1. 程式人生 > >【CodeChef】Annual Parade -最小費用最大流&無向圖最小鏈覆蓋

【CodeChef】Annual Parade -最小費用最大流&無向圖最小鏈覆蓋

傳送門: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;
}