[NOI2006] 最大获利

link

一道不算太难的网络流模型题目。

显然可以发现对于每一个用户可能会有哪些决策。无非就是两种,一种是牺牲自己,但换来了基站那边的平易近人;另一种是自己付费,但同时自己对应的两个基站都要建立。这样我们就可以抽象化两个决策了,假如每个用户都付了钱的,那么要么会损失这个用户的费用,要么会损失建立两个基站的费用,而我们需要的就是最小化这个值,那么这就是一个可爱的网络流模板了。

鬼知道为什么卡我空间,开大二倍就好了。

#include<cstdio>
//#define zczc
const int N=10010;
const int M=100010;
const int maxn=1e9;
inline void read(int &wh){
	wh=0;int f=1;char w=getchar();
	while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
	while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
	wh*=f;return;
}
inline int min(int s1,int s2){
	return s1<s2?s1:s2;
}

struct edge{
	int t,v,next;
}e[N+M<<2];
int esum=1,head[N+M];
inline void adde(int fr,int to,int val){
	e[++esum]=(edge){to,val,head[fr]};head[fr]=esum;
}
inline void add(int fr,int to,int val){
	adde(fr,to,val);adde(to,fr,0);
}

int ans,m,n,s1,s2,in;
int cnt,s,t,a[N],b[M];//每个基站和每个用户的节点 

int q[N+M],l,r,d[N+M];
inline bool check(int wh){
	for(int i=1;i<=cnt;i++)d[i]=0;
	d[q[l=r]=s]=1;
	while(l<=r)
		for(int i=head[wh=q[l++]],th;i;i=e[i].next)
			if(e[i].v&&d[th=e[i].t]==0)q[++r]=th,d[th]=d[wh]+1;
	return d[t];
}
int dinic(int wh,int val){
	if(wh==t)return val;int cost=0;
	for(int i=head[wh],th;i;i=e[i].next){
		if(e[i].v==0||d[th=e[i].t]!=d[wh]+1)continue;
		int now=dinic(th,min(val,e[i].v));
		e[i].v-=now,e[i^1].v+=now;
		cost+=now,val-=now;if(val==0)break;
	}
	return d[wh]=val?0:d[wh],cost;
}

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	s=++cnt;t=++cnt;
	read(m);read(n);
	for(int i=1;i<=m;i++){
		read(in);a[i]=++cnt;
		add(s,a[i],in);
	}
	for(int i=1;i<=n;i++){
		read(s1);read(s2);read(in);b[i]=++cnt;
		add(a[s1],b[i],maxn);
		add(a[s2],b[i],maxn);
		add(b[i],t,in);ans+=in;
	}
	while(check(0))ans-=dinic(s,maxn);
	printf("%d\n",ans);
	
	return 0;
}
posted @ 2022-03-05 12:55  Feyn618  阅读(40)  评论(0)    收藏  举报