P4553 80人环游世界(上下界费用流)

P4553 80人环游世界

emm......先从上下界网络流(转)开始

再到现在的上下界费用流

因为有上下界,我们需要记下每个点的流量差$ex[i]$,用于调整

$ins(x,y,l,r,v)=link(x,y,r-l,v),ex[x]-=l,ex[y]+=l$

每个点都得经过$w$次,等价于:

把每个点$i$拆成$i_1,i_2$,$ins(i_1,i_2,w,w,0)$

题目限制总流量$=m$,于是设置一个附加点$T0$,$ins(T0,T,0,m,0)$,(最终一定会流满$m$)

对于其他点,也套路地连边:

$ins(S,i_1,0,m,0)$

$ins(i_2,T0,0,m,0)$

对于两点之间的边$(i,j,w)$:$ins(i_2,j_1,0,m,w)$

使源汇点流量守恒:$ins(T,S,0,m,0)$

 

蓝后就是对原图的调整(原图可能有些点不流量守恒):

按照上下界网络流的套路,新建调整源点汇点$pS,pT$

$if(ex[i]<0) link(i,pT,-ex[i],0);$
$if(ex[i]>0) link(pS,i,ex[i],0);$

最后直接以$pS,pT$为源点汇点跑费用流

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define N 2005
#define M 100005
int n,m,S,T0,T,pS,pT,ex[N],d[N],a[N],p[N],tC;
queue <int> h; bool inh[N];
int cnt=1,hd[N],nxt[M],ed[N],poi[M],val[M],cst[M];
inline void adde(int x,int y,int v1,int v2){
    nxt[ed[x]]=++cnt, hd[x]=hd[x]?hd[x]:cnt,
    ed[x]=cnt, poi[cnt]=y, val[cnt]=v1,cst[cnt]=v2;
}
inline void link(int x,int y,int v1,int v2){adde(x,y,v1,v2),adde(y,x,0,-v2);}
inline void ins(int x,int y,int l,int r,int v){link(x,y,r-l,v),ex[x]-=l,ex[y]+=l;}
bool bfs(){
    memset(d,127,sizeof(d)); int inf=d[0];
    h.push(S); d[S]=0; a[S]=inf; inh[S]=1;
    while(!h.empty()){
        int x=h.front(); h.pop(); inh[x]=0;
        for(int i=hd[x];i;i=nxt[i]){
            int to=poi[i];
            if(val[i]>0&&d[to]>d[x]+cst[i]){
                d[to]=d[x]+cst[i]; p[to]=i;
                a[to]=min(a[x],val[i]);
                if(!inh[to]) inh[to]=1,h.push(to);
            }
        }
    }if(d[T]==inf) return 0;
    tC+=a[T]*d[T];
    for(int i=T;i!=S;i=poi[p[i]^1])
        val[p[i]]-=a[T],val[p[i]^1]+=a[T];
    return 1;
}
int main(){
    scanf("%d%d",&n,&m); int w;
    S=2*n+1; T0=S+1; T=T0+1; pS=T+1; pT=pS+1;
    ins(T0,T,0,m,0);
    for(int i=1;i<=n;++i){
        ins(S,i,0,m,0);
        ins(i+n,T0,0,m,0);
        scanf("%d",&w);
        ins(i,i+n,w,w,0);
    }
    for(int i=1;i<=n;++i)
        for(int j=i+1;j<=n;++j){
            scanf("%d",&w);
            if(w>-1) ins(i+n,j,0,m,w);
        }
    for(int i=1;i<=T;++i){//调整
        if(ex[i]<0) link(i,pT,-ex[i],0);
        if(ex[i]>0) link(pS,i,ex[i],0);
    }ins(T,S,0,m,0);
    swap(S,pS);swap(T,pT);
    while(bfs());
    printf("%d",tC);
    return 0;
}

 

 

转载于:https://www.cnblogs.com/kafuuchino/p/10803659.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《Python八十天环游世界》是一本以Python编程语言为主题的书籍,它通过一系列有趣的项目和挑战,帮助读者掌握Python的各种应用和技巧。这本书的目标是帮助读者在八十天内通过实践来提高他们的Python编程能力,并且了解Python在不同领域的应用。 这本书通常会涵盖以下内容: 1. Python基础知识:包括变量、数据类型、条件语句、循环语句等基本概念和语法。 2. 函数和模块:介绍如何定义和使用函数,以及如何使用Python的模块来组织代码。 3. 文件操作:学习如何读写文件,以及如何处理CSV、JSON等常见文件格式。 4. 网络编程:了解如何使用Python进行网络通信,包括HTTP请求、Socket编程等。 5. 数据库操作:介绍如何使用Python连接和操作数据库,如MySQL、SQLite等。 6. Web开发:学习使用Python的Web框架(如Django、Flask)来构建网站和Web应用程序。 7. 数据分析和可视化:了解如何使用Python进行数据分析和可视化,如Pandas、Matplotlib等库的使用。 8. 机器学习和人工智能:介绍如何使用Python进行机器学习和人工智能的开发,如Scikit-learn、TensorFlow等。 通过完成这本书中的项目和挑战,读者可以逐步提高他们的Python编程能力,并且了解Python在不同领域的应用。这本书适合已经具备一定Python基础的读者,希望通过实践来进一步提升自己的编程技能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值