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# 5.0 新特性——Async和Await使异步编程更简单
    [C# 开发技巧系列]使用C#操作Word和Excel程序
    全面解析C#中参数传递
    VSTO之旅系列(四):创建Word解决方案
    [C# 开发技巧系列] 使用C#操作幻灯片
    VSTO之旅系列(五):创建Outlook解决方案
    [C# 开发技巧系列]C#如何实现图片查看器
    [你必须知道的异步编程]——异步编程模型(APM)
    [你必须知道的异步编程]——基于任务的异步模式
    [C# 开发技巧系列]如何动态设置屏幕分辨率
  • 原文地址:https://www.cnblogs.com/lytccc/p/7010161.html
Copyright © 2011-2022 走看看