bzoj千题计划159:bzoj2055: 80人环游世界(上下界费用流)

http://www.lydsy.com/JudgeOnline/problem.php?id=2055

某个国家必须经过vi次,

可以转化为上下界都为vi的边

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 205
#define M 10500

const int inf=1e9;

int src,decc;
int S,T;

int tot=1;
int front[N],to[M<<1],nxt[M<<1],cap[M<<1],val[M<<1],from[M<<1];

int cost;

int dis[N];
bool vis[N];

void read(int &x)
{
    x=0;  int f=1; char c=getchar();
    while(!isdigit(c)) { if(c==‘-‘) f=-1; c=getchar(); }
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); }
    x*=f;
}

void add(int u,int v,int w,int f)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u; cap[tot]=w; val[tot]=f;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; from[tot]=v; cap[tot]=0; val[tot]=-f;
}

int agument(int now,int flow)
{
    vis[now]=true;
    if(now==T)
    {
        cost-=dis[S]*flow;
        return flow;
    }
    int delta;
    for(int i=front[now];i;i=nxt[i])
    {
        if(cap[i] && !vis[to[i]] && dis[to[i]]==dis[now]+val[i])
        {
            delta=agument(to[i],min(flow,cap[i]));
            if(delta)
            {
                cap[i]-=delta;
                cap[i^1]+=delta;
                return delta;
            }
        }
    }
    return 0;
}

bool retreat()
{
    if(vis[T]) return true;
    int mi=inf;
    for(int i=2;i<=tot;++i)
        if(cap[i] && vis[from[i]] && !vis[to[i]])
            mi=min(mi,dis[from[i]]+val[i]-dis[to[i]]);
    if(mi==inf) return false;
    for(int i=0;i<=T;++i)
        if(vis[i]) dis[i]-=mi;
    return true;
}

void zkw()
{
    do
    {
        memset(vis,false,sizeof(vis));
        agument(S,inf);
    }while(retreat());
    cout<<cost;
}

int main()
{
    int n,m;
    read(n); read(m);
    src=1; decc=(n<<1|1)+1; T=decc+1;
    int x;
    for(int i=1;i<=n;++i)
    {
        read(x);
        if(!x) continue;
        add(i<<1,T,x,0);
        add(S,i<<1|1,x,0);
    }
    int k;
    for(int i=1;i<n;++i)
    {
        for(int j=i+1;j<=n;++j)
        {
            read(x);
            if(x==-1) continue;
            add(i<<1|1,j<<1,m,x);
        }
    }
    for(int i=1;i<=n;++i) add(1,i<<1,m,0);
    add(S,1,m,0);
    add(decc,T,m,0);
    add(decc,src,m,0);
    zkw();
}

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 205
#define M 10500

const int inf=1e9;

int src,decc;
int S,T;

int tot=1;
int front[N],to[M<<1],nxt[M<<1],cap[M<<1],val[M<<1],from[M<<1];

int cost;

int dis[N];
bool vis[N];

void read(int &x)
{
    x=0;  int f=1; char c=getchar();
    while(!isdigit(c)) { if(c==‘-‘) f=-1; c=getchar(); }
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); }
    x*=f;
}

void add(int u,int v,int w,int f)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u; cap[tot]=w; val[tot]=f;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; from[tot]=v; cap[tot]=0; val[tot]=-f;
}

int agument(int now,int flow)
{
    vis[now]=true;
    if(now==decc)
    {
        cost-=dis[S]*flow;
        return flow;
    }
    int delta;
    for(int i=front[now];i;i=nxt[i])
    {
        if(cap[i] && !vis[to[i]] && dis[to[i]]==dis[now]+val[i])
        {
            delta=agument(to[i],min(flow,cap[i]));
            if(delta)
            {
                cap[i]-=delta;
                cap[i^1]+=delta;
                return delta;
            }
        }
    }
    return 0;
}

bool retreat()
{
    if(vis[decc]) return true;
    int mi=inf;
    for(int i=2;i<=tot;++i)
        if(cap[i] && vis[from[i]] && !vis[to[i]])
            mi=min(mi,dis[from[i]]+val[i]-dis[to[i]]);
    if(mi==inf) return false;
    for(int i=0;i<=decc;++i)
        if(vis[i]) dis[i]-=mi;
    return true;
}

void zkw()
{
    do
    {
        memset(vis,false,sizeof(vis));
        agument(S,inf);
    }while(retreat());
    cout<<cost;
}

int main()
{
    int n,m;
    read(n); read(m);
    src=1; decc=(n<<1|1)+1;
    int x;
    for(int i=1;i<=n;++i)
    {
        read(x);
        if(!x) continue;
        add(i<<1,decc,x,0);
        add(S,i<<1|1,x,0);
    }
    int k;
    for(int i=1;i<n;++i)
    {
        for(int j=i+1;j<=n;++j)
        {
            read(x);
            if(x==-1) continue;
            add(i<<1|1,j<<1,m,x);
        }
    }
    for(int i=1;i<=n;++i) add(1,i<<1,m,0);
    add(S,1,m,0);
    zkw();
}

时间: 2024-10-14 13:10:08

bzoj千题计划159:bzoj2055: 80人环游世界(上下界费用流)的相关文章

【BZOJ-2055】80人环游世界 上下界费用流 (无源无汇最小费用最大流)

2055: 80人环游世界 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 321  Solved: 201[Submit][Status][Discuss] Description 想必大家都看过成龙大哥的<80天环游世界>,里面的紧张刺激的打斗场面一定给你留下了深刻的印象.现在就有这么 一个80人的团伙,也想来一次环游世界. 他们打算兵分多路,游遍每一个国家. 因为他们主要分布在东方,所以他们只朝西方进军.设从东方到西方的每一个国家的编号依次为

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

题意: 有1-n个城市  有m个人去旅游  每个人只能从编号小的城市到编号大的城市  花费费用为COSTij   一开始每个人可以从任意一个城市开始旅行   且每个城市恰好有Vi个人经过(一开始也算经过) 问最小花费 显然用有上下界的费用流非常好理解  每个点进行拆点 两点之间连上界和下界都为Vi 表示正好通过Vi人      然后经典连图即可 再控制一下人数m  跑模板 (正面建图) #include<bits/stdc++.h> using namespace std; //input b

bzoj 2055: 80人环游世界 -- 上下界网络流

2055: 80人环游世界 Time Limit: 10 Sec  Memory Limit: 64 MB Description 想必大家都看过成龙大哥的<80天环游世界>,里面的紧张刺激的打斗场面一定给你留下了深刻的印象.现在就有这么 一个80人的团伙,也想来一次环游世界. 他们打算兵分多路,游遍每一个国家. 因为他们主要分布在东方,所以他们只朝西方进军.设从东方到西方的每一个国家的编号依次为1...N.假若第i个人的游历路线为P1.P2......Pk(0≤k≤N),则P1<P2&

BZOJ2055 80人环游世界

m个人随便设定起点= =,所以是有上下界网络流喽... 今天刚学,于是试着写了写,1A耶! 费用流是板子哦~ 1 /************************************************************** 2 Problem: 2055 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:536 ms 7 Memory:8624 kb 8 ******************************

[bzoj2055]80人环游世界[网络流,上下界网络流]

手动画了整张图,,算是搞懂了吧,, 1 #include <bits/stdc++.h> 2 3 #define INF 0x3f3f3f3f 4 5 using namespace std; 6 7 template<const int _n,const int _m> 8 struct Edge 9 { 10 struct Edge_base { int to,next,w,c; }e[_m]; int cnt,p[_n]; 11 Edge() { clear(); } 12

bzoj2055: 80人环游世界(可行流)

传送门 表示完全看不懂最小费用可行流…… 据某大佬说 我们考虑拆点,然后进行如下连边 $s$向$a_i$连边,权值$0$,容量$[0,m]$ $a_i$向$a_i'$连边,权值$0$容量$[v_i,v_i]$ 如果存在边$(i,j)$,则连边$a_i'->a_i$,权值为$w_{i,j}$,容量$[0,m]$ $a_i'$向$t$连边,权值$0$,容量$[0,m]$ $t$向$t'$连边,权值$0$容量$[0,m]$ 然后跑个最小费用可行流 1 //minamoto 2 #include<io

【bzoj2055】80人环游世界 有上下界费用流

原文地址:http://www.cnblogs.com/GXZlegend 题目描述 想必大家都看过成龙大哥的<80天环游世界>,里面的紧张刺激的打斗场面一定给你留下了深刻的印象.现在就有这么 一个80人的团伙,也想来一次环游世界. 他们打算兵分多路,游遍每一个国家. 因为他们主要分布在东方,所以他们只朝西方进军.设从东方到西方的每一个国家的编号依次为1...N.假若第i个人的游历路线为P1.P2......Pk(0≤k≤N),则P1<P2<......<Pk. 众所周知,中

bzoj 2055 80人环游世界

有源汇上下界最小费用可行流. 将每个国家拆点. 源点向一个新建节点连一条上界为总人数下界为0费用为0的边. 新建节点向每个国家的入点连一条上界为正无穷下界为0费用为0的边. 每个国家的入点向出点连一条上下界均为该国家访问人数费用为0的边. 每个国家的出点向汇点连一条上界为正无穷下界为0费用为0的边. 对于国家i能到国家j,i的出点向j的入点连一条上界为正无穷下界为0费用为机票费的边. 然后对图求一边有源汇上下界最小费用可行流即可得出最小费用. 具体做法是先将所有边的下界乘费用相加,这一部分是必须

bzoj千题计划238:bzoj3668: [Noi2014]起床困难综合症

http://www.lydsy.com/JudgeOnline/problem.php?id=3668 这..一位一位的来就好了呀 #include<cstdio> #include<iostream> using namespace std; #define N 100001 struct node { int ty,t; }e[N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=get