zoukankan      html  css  js  c++  java
  • BZOJ 2055 80人环游世界

    80人环游世界

    【问题描述】

      想必大家都看过成龙大哥的《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

    【样例输出】

    1<= N < =100 1<= M <= 79


    题解:

    题意是求 m 个人(每个人起始点任意)通过路径经过第 i 个国家恰好 v[i] 次的最小费用

    考虑有上下界无源汇可行最小费用循环流

    每个点拆成两个点,一个入,一个出

    一个点向另一个点连上界下界均为 v[i] 的边,其它边下界均为 0

    对于流量为 m 和任意起始点要求

    我们新建一个点,从超级源向这个点连容量为 m 的边

    再从这个点向每一个入点连一条无上界的边

    其实就是在原图中的源点向这个点连下界为 m 的边

    其余的按照题意建

      1 #include<cmath>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<iostream>
      6 #include<algorithm>
      7 using namespace std;
      8 const int maxn = 233;
      9 const int maxm = maxn * maxn;
     10 const int inf = 1e9;
     11 int num;
     12 int fir[maxn], nex[maxm], ver[maxm], con[maxm], pri[maxm];
     13 inline void Scan(int &x)
     14 {
     15     char c;
     16     bool o = false;
     17     while(!isdigit(c = getchar())) o = (c != '-') ? o : true;
     18     x = c - '0';
     19     while(isdigit(c = getchar())) x = x * 10 + c - '0';
     20     if(o) x = -x;
     21 }
     22 inline void Ins(int x, int y, int z, int v)
     23 {
     24     nex[++num] = fir[x];
     25     fir[x] = num;
     26     ver[num] = y;
     27     con[num] = z;
     28     pri[num] = v;
     29 }
     30 inline void Add(int x, int y, int z, int v)
     31 {
     32     printf("%d %d %d
    ", x, y, z);
     33     Ins(x, y, z, v);
     34     Ins(y, x, 0, -v);
     35 }
     36 int du[maxn];
     37 inline void Put(int x, int y, int l, int r, int v)
     38 {
     39     du[x] -= l, du[y] += l;
     40     Add(x, y, r - l, v);
     41 }
     42 int s, t, nors, nort, supers, supert;
     43 int que[maxm], dis[maxn];
     44 bool vis[maxn];
     45 inline bool Spfa()
     46 {
     47     int head = 0, tail = 1;
     48     memset(dis, 127 / 2, sizeof(dis));
     49     que[tail] = s;
     50     dis[s] = 0;
     51     vis[s] = true;
     52     while(head < tail)
     53     {
     54         int u = que[++head];
     55         for(int i = fir[u]; i; i = nex[i])
     56         {
     57             if(!con[i]) continue;
     58             int v = ver[i];
     59             if(dis[v] > dis[u] + pri[i])
     60             {
     61                 dis[v] = dis[u] + pri[i];
     62                 if(!vis[v])
     63                 {
     64                     vis[v] = true;
     65                     que[++tail] = v;
     66                 }
     67             }
     68         }
     69         vis[u] = false;
     70     }
     71     return dis[t] < inf;
     72 }
     73 int ans;
     74 bool mark[maxn];
     75 int Dinic(int u, int flow)
     76 {
     77     mark[u] = true;
     78     if(u == t) return flow;
     79     int left = flow;
     80     for(int i = fir[u]; i; i = nex[i])
     81     {
     82         if(!con[i]) continue;
     83         int v = ver[i];
     84         if(mark[v] || dis[v] != dis[u] + pri[i]) continue;
     85         int go = Dinic(v, min(con[i], left));
     86         if(go)
     87         {
     88             con[i] -= go;
     89             con[i ^ 1] += go;
     90             left -= go;
     91             ans += go * pri[i];
     92             if(!left) return flow;
     93         }
     94     }
     95     return flow - left;
     96 }
     97 int n, m;
     98 inline void Set()
     99 {
    100     num = 1;
    101     nors = n << 1 | 1;
    102     nort = nors + 1;
    103     supers = nort + 1;
    104     supert = supers + 1;
    105 }
    106 inline void Flow(int x, int y)
    107 {
    108     s = x, t = y;
    109     while(Spfa())
    110     {
    111         memset(mark, false, sizeof(mark));
    112         Dinic(s, inf);
    113     }
    114 }
    115 int main()
    116 {
    117     Scan(n), Scan(m);
    118     Set();
    119     int v;
    120     for(int i = 1; i <= n; ++i)
    121     {
    122         Scan(v);
    123         Add(nors, i, inf, 0);
    124         Put(i, i + n, v, v, 0);
    125     }
    126     for(int i = 1; i <= n; ++i)
    127         for(int j = i + 1; j <= n; ++j)
    128         {
    129             Scan(v);
    130             if(v != -1) Add(i + n, j, inf, v);
    131         }
    132     for(int i = 1; i <= supert; ++i)
    133     {
    134         if(du[i] > 0) Add(supers, i, du[i], 0);
    135         if(du[i] < 0) Add(i, supert, -du[i], 0);
    136     }
    137     Add(supers, nors, m, 0);
    138     Flow(supers, supert);
    139     printf("%d", ans);
    140 }
  • 相关阅读:
    在C#代码中应用Log4Net(二)典型的使用方式
    在C#代码中应用Log4Net(一)简单使用Log4Net
    Windows Azure Active Directory (2) Windows Azure AD基础
    Windows Azure Virtual Network (6) 设置Azure Virtual Machine固定公网IP (Virtual IP Address, VIP) (1)
    Windows Azure Active Directory (1) 前言
    Azure China (6) SAP 应用在华登陆 Windows Azure 公有云
    Microsoft Azure News(3) Azure新的基本实例上线 (Basic Virtual Machine)
    Microsoft Azure News(2) 在Microsoft Azure上运行SAP应用程序
    Microsoft Azure News(1) 新的数据中心Japan East, Japan West and Brazil South
    Windows Azure HandBook (2) Azure China提供的服务
  • 原文地址:https://www.cnblogs.com/lytccc/p/7010161.html
Copyright © 2011-2022 走看看