zoukankan      html  css  js  c++  java
  • 【bzoj2055】80人环游世界 有上下界费用流

    原文地址:http://www.cnblogs.com/GXZlegend


    题目描述

    想必大家都看过成龙大哥的《80天环游世界》,里面的紧张刺激的打斗场面一定给你留下了深刻的印象。现在就有这么
    一个80人的团伙,也想来一次环游世界。
    他们打算兵分多路,游遍每一个国家。
    因为他们主要分布在东方,所以他们只朝西方进军。设从东方到西方的每一个国家的编号依次为1...N。假若第i个人的游历路线为P1、P2......Pk(0≤k≤N),则P1<P2<......<Pk。
    众所周知,中国相当美丽,这样在环游世界时就有很多人经过中国。我们用一个正整数Vi来描述一个国家的吸引程度,Vi值越大表示该国家越有吸引力,同时也表示有且仅
    有Vi个人会经过那一个国家。
    为了节省时间,他们打算通过坐飞机来完成环游世界的任务。同时为了省钱,他们希望总的机票费最小。
    明天就要出发了,可是有些人临阵脱逃,最终只剩下了M个人去环游世界。他们想知道最少的总费用,你能告诉他们吗?

    输入

    第一行两个正整数N,M。
    第二行有N个不大于M正整数,分别表示V1,V2......VN。
    接下来有N-1行。第i行有N-i个整数,该行的第j个数表示从第i个国家到第i+j个国家的机票费(如果该值等于-1则表示这两个国家间没有通航)。

    输出

    在第一行输出最少的总费用。

    样例输入

    6 3
    2 1 3 1 2 1
    2 6 8 5 0
    8 2 4 1
    6 1 0
    4 -1
    4

    样例输出

    27


    题解

    有上下界费用流

    题目中说每个点需要经过固定的次数,那么我们可以拆点,并在拆出来的两个点之间连一条上下界均为vi的边。

    建图通法可以参考 bzoj3876 ,对于这道题的具体建图方法:

    2*n+1->0(m,0)(用于限制流量)

    0->i(inf,0)

    i+n->2*n+1(inf,0)(将有源汇转化为无源汇)

    s->i+n(vi,0),i->t(vi,0)

    i+n->j(inf,cost[i][j])(i<j)

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define inf 0x3f3f3f3f
    using namespace std;
    queue<int> q;
    int head[210] , to[500010] , val[500010] , cost[500010] , next[500010] , cnt = 1 , cd[210] , s , t , dis[210] , from[210] , pre[210];
    void add(int x , int y , int v , int c)
    {
    	to[++cnt] = y , val[cnt] = v , cost[cnt] = c , next[cnt] = head[x] , head[x] = cnt;
    	to[++cnt] = x , val[cnt] = 0 , cost[cnt] = -c , next[cnt] = head[y] , head[y] = cnt;
    }
    bool spfa()
    {
    	int x , i;
    	memset(dis , 0x3f , sizeof(dis));
    	memset(from , -1 , sizeof(from));
    	dis[s] = 0 , q.push(s);
    	while(!q.empty())
    	{
    		x = q.front() , q.pop();
    		for(i = head[x] ; i ; i = next[i])
    			if(val[i] && dis[to[i]] > dis[x] + cost[i])
    				dis[to[i]] = dis[x] + cost[i] , from[to[i]] = x , pre[to[i]] = i , q.push(to[i]);
    	}
    	return ~from[t];
    }
    int mincost()
    {
    	int ans = 0 , i , k;
    	while(spfa())
    	{
    		k = inf;
    		for(i = t ; i != s ; i = from[i]) k = min(k , val[pre[i]]);
    		ans += dis[t] * k;
    		for(i = t ; i != s ; i = from[i]) val[pre[i]] -= k , val[pre[i] ^ 1] += k;
    	}
    	return ans;
    }
    int main()
    {
    	int n , m , i , j , x;
    	scanf("%d%d" , &n , &m) , s = 2 * n + 2 , t = 2 * n + 3;
    	add(2 * n + 1 , 0 , m , 0);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &x) , add(0 , i , inf , 0) , add(i + n , 2 * n + 1 , inf , 0) , add(s , i + n , x , 0) , add(i , t , x , 0);
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		for(j = i + 1 ; j <= n ; j ++ )
    		{
    			scanf("%d" , &x);
    			if(~x) add(i + n , j , inf , x);
    		}
    	}
    	printf("%d
    " , mincost());
    	return 0;
    }

     

  • 相关阅读:
    ModuleNotFoundError: No module named 'babel' 解决办法
    linux修改时间
    Ubuntu 18.04 安装 odoo12 源码版
    开源ERP框架Odoo学习
    浅谈我对DDD领域驱动设计的理解(转)
    一步步带你做vue后台管理框架
    一步一步使用ABP框架搭建正式项目系列教程
    C#编写好的windows服务,在本机上运行很好,考到其他电脑运行出现“错误1053: 服务没有及时响应启动或控制请求”的解决办法
    公用表表达示展BOM示例
    sqlserver 2005新功能
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6832385.html
Copyright © 2011-2022 走看看