[NOI2006] 最大获利
一道不算太难的网络流模型题目。
显然可以发现对于每一个用户可能会有哪些决策。无非就是两种,一种是牺牲自己,但换来了基站那边的平易近人;另一种是自己付费,但同时自己对应的两个基站都要建立。这样我们就可以抽象化两个决策了,假如每个用户都付了钱的,那么要么会损失这个用户的费用,要么会损失建立两个基站的费用,而我们需要的就是最小化这个值,那么这就是一个可爱的网络流模板了。
鬼知道为什么卡我空间,开大二倍就好了。
#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;
}
一如既往,万事胜意

浙公网安备 33010602011771号