[AHOI2014/JSOI2014]支线剧情 有源汇上下界可行流(等等这题好像没有上界)

---恢复内容开始---

大脑有点晕。先做点水题练练手吧。(主要是在下网络流太菜,准备复习下)

每个剧情都要看,那就是每条边都要走一次嘛。不说了,费用流模板,把所有边的流量下限置为1,直接跑就行了。

默认无源汇上下界的大家都会做。

那么,从汇点向源点连一条费用为0,流量无限的边就满足所有点都流量守恒了,转为无源汇上下界模型。

代码不长。(然而我写得丑还是要承认的。)

#include<bits/stdc++.h>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<vector>
#include<iostream>
#define ll long long
#define re register
#define inf 0x3f3f3f3f
#define inl inline
#define sqr(x) (x*x)
//#define eps 1e-8
#define debug printf("debug
");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
//#pragma GCC optimize (2)
//#pragma G++ optimize (2)
using namespace std;
const ll mod=51123987;
const ll MAXN=505;
inl ll read() {
    re ll x = 0; re int f = 1;
    char ch = getchar();
    while(ch<'0'||ch>'9') { if(ch== '-' ) f = -1; ch = getchar(); }
    while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x * f;
}
inl char readc() {
    char ch=getchar();
    while(('z'<ch||ch<'a')&&('Z'<ch||ch<'A')) ch=getchar();
    return ch;
}
inl void write(re ll x){
    if(x>=10)write(x/10);
    putchar(x%10+'0');
}
inl void writeln(re ll x){
    if(x<0) {x=-x;putchar('-');}
    write(x); puts("");
}
inl ll gcd(re ll x,re ll y){while(y^=x^=y^=x%=y);return x;}
inl ll Lcm(re ll a,re ll b) {return a/gcd(a,b)*b;}
inl void FR() {
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
}
inl void FC() {
    fclose(stdin);
    fclose(stdout);
}
ll head[MAXN],cnt;
struct edge {
    ll u,v,w,nxt,val,pd;
}e[(MAXN*MAXN)<<1];
inl void adde(ll u,ll v,ll w,ll val) {
    e[++cnt].u=u;e[cnt].v=v;e[cnt].w=w;
    e[cnt].val=val;e[cnt].nxt=head[u];head[u]=cnt;
}
ll ans,n,dis[MAXN],cur[MAXN];
ll sum[MAXN],pre[MAXN],flow[MAXN];
bool in[MAXN];
bool spfa() {
    memset(dis,inf,sizeof(dis));
    deque<ll>Q;
    while(!Q.empty()) Q.pop_back();
    Q.push_back(0);in[0]=1;dis[0]=0;flow[0]=inf;
    while(!Q.empty()) {
        ll x=Q.front();Q.pop_front();in[x]=0;
        for(re ll h=head[x];h;h=e[h].nxt) {
            if(e[h].w<=0) continue ;
            re ll v=e[h].v;
            if(dis[v]<=dis[x]+e[h].val) continue ;
            dis[v]=dis[x]+e[h].val;
            pre[v]=h;flow[v]=min(flow[x],e[h].w);
            if(in[v]) continue ;
            if(Q.empty()||dis[v]<dis[Q.front()]) {Q.push_front(v);in[v]=1;}
            else {Q.push_back(v);in[v]=1; }
        }
    }
    return dis[n+2]-dis[n+3];
}
ll dinic() {
    ll sum=0;
    while(spfa()) {
        ll x=n+2;
        while(x!=0) {
            ll h=pre[x];e[h].w-=flow[n+2];
            e[e[h].pd].w+=flow[n+2];x=e[h].u;
        }
        ans+=flow[n+2]*dis[n+2];
    }
    return sum;
}
int main() {
//  FR();
    n=read();ans=0;
    for(re ll i=1;i<=n;i++) {
        re ll x=read();
        for(re ll j=1;j<=x;j++) {
            re ll v=read(),val=read();
            ans+=val;sum[i]--;sum[v]++;
            adde(i,v,inf,val);e[cnt].pd=cnt+1;
            adde(v,i,0,-val);e[cnt].pd=cnt-1;
        }
    }
    for(re ll i=2;i<=n;i++) {
        adde(i,n+1,inf,0);e[cnt].pd=cnt+1;
        adde(n+1,i,0,0);e[cnt].pd=cnt-1;
    }
    for(re ll i=1;i<=n;i++) {
        if(sum[i]>0) {
            adde(0,i,sum[i],0);e[cnt].pd=cnt+1;
            adde(i,0,0,0);e[cnt].pd=cnt-1;
        }
        if(sum[i]<0) {
            adde(i,n+2,-sum[i],0);e[cnt].pd=cnt+1;
            adde(n+2,i,0,0);e[cnt].pd=cnt-1;
        }
    }
    adde(n+1,1,inf,0);e[cnt].pd=cnt+1;//加上从汇点到原点的,费用为0,就满足所有点流量平衡,当做无源汇来做了 
    adde(n+1,1,inf,0);e[cnt].pd=cnt-1;
    dinic();
    writeln(ans);
//  FC();
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/20020723YJX/p/9404288.html