牛客練習賽51- F 發傳單(網絡流)

題目鏈接

F 發傳單

題意:

一個人有 nn 個朋友,這個人有很多傳單,他可以將傳單發給所有朋友,對於發給第 ii 個人需要 wiw_i 的費用,他的朋友之間也有相互認識可以將傳單給其他人,也需要一些費用,告訴你具體的朋友之間的認識關係和費用,要求這個人在使用最少的傳單數下用最少的總費用,使得朋友都看過傳單。

思路:

由於要求每一個朋友都看過,那麼可以將每一個朋友進行拆點 (i,i+n)(i,i+n) 那麼這兩點之間的流量一定要大於等於 11 ,將人做爲源點 ss 按照題意建邊,建立一個匯點 tt ,向所有的朋友右端點連向 tt ,由於要求使用最小的傳單數,參考一血的代碼,可以將人向每一個朋友傳單的費用變爲 wi+infw_i+inf ,最後 ans%infans\%inf 就行了,因爲是最小費用,所以可以使得所用的傳單最小。現在就只要建立超級源點 SS 和超級匯點 TT 就可以跑有上下界的最小費用最大流了。

代碼:

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int N=1e5+10;
const int M=1e6+10;
const int mx=2e6;
struct MCMF{
	int h[N],ne[M],to[M],flow[M],w[M],tot,dis[N],liu[N],pre[N],inq[N],s,t;
	int ans;
	void init(int a,int b){
		s=a;t=b;
		for(int i=0;i<M;i++)ne[i]=0;
		for(int i=0;i<N;i++)h[i]=0;
		tot=1;ans=0;
	}
	void addedge(int x,int y,int z,int c){
		to[++tot]=y;ne[tot]=h[x],h[x]=tot,flow[tot]=z;w[tot]=c;
		swap(x,y);
		to[++tot]=y;ne[tot]=h[x],h[x]=tot,flow[tot]=0;w[tot]=-c;
	}
	int bfs(){
		for(int i=0;i<=t;i++)dis[i]=inf,liu[i]=inf,inq[i]=pre[i]=0;
		queue<int>q;int x;dis[s]=0;q.push(s);
		while(!q.empty()){
			x=q.front();q.pop();inq[x]=0;
			for(int i=h[x];i;i=ne[i]){
				int v=to[i];
				if(flow[i]>0&&dis[x]+w[i]<dis[v]){
					dis[v]=dis[x]+w[i],pre[v]=i;
					liu[v]=min(liu[x],flow[i]);
					if(!inq[v])inq[v]=1,q.push(v);
				}
			}
		}
		if(!pre[t])return 0;
		x=t;ans+=dis[t]*liu[t];
		while(x!=s){
			int kl=pre[x];
			flow[kl]-=liu[t];flow[kl^1]+=liu[t];x=to[kl^1];
		}
		return 1;
	}
	int mcmf(){
		while(bfs()){}
		return ans;
	}
}F;
int d[N];
void add(int u,int v,int down,int up,int w){
	F.addedge(u,v,up-down,w);
	d[u]-=down,d[v]+=down;
}
int n,s,t,S,T;
int main()
{
	scanf("%d",&n);s=2*n+1;t=2*n+2;S=2*n+3,T=2*n+4;
	F.init(S,T);//初始化
	add(t,s,0,inf,0);//變成無匯源
	for(int i=1,x;i<=n;i++){
		scanf("%d",&x);
		add(s,i,0,inf,x+mx);
	}
	for(int i=1;i<=n;i++){
		int tt,x,y;
		add(i,i+n,1,inf,0);//下界大於一
		add(i+n,t,0,inf,0);
		scanf("%d",&tt);
		while(tt--){
			scanf("%d%d",&x,&y);
			add(i+n,x,0,inf,y);
		}
	}
	for(int i=1;i<=t;i++)if(d[i]>0)F.addedge(S,i,d[i],0);else if(d[i]<0)F.addedge(i,T,-d[i],0);
	cout<<F.mcmf()%mx<<endl;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章