zoukankan      html  css  js  c++  java
  • ZOJ-2770 Burn the Linked Camp---差分约束系统

    题目链接:

    https://vjudge.net/problem/ZOJ-2770

    题目大意:

    大家都知道,三国时期,蜀国刘备被吴国大都督陆逊打败了。刘备失败的原因是因为刘备的错误决策。他把部队分成几十个大营,每个大营驻扎一队部队,又用树木编成栅栏,把大营连成一片,称为连营。
    让我们回到那个时代。陆逊派了很多密探,获得了他的敌人-刘备的信息。通过密探,他知道刘备的部队已经分成几十个大营,这些大营连成一片(一字排开),这些大营从左到右用1...n编号。第i个大营最多能容纳Ci个士兵。而且通过观察刘备军队的动静,陆逊可以估计到从第i个大营到第j个大营至少有多少士兵。最后,陆逊必须估计出刘备最少有多少士兵,这样他才知道要派多少士兵去烧刘备的大营。
    为陆逊估计出刘备军队至少有多少士兵。然而,陆逊的估计可能不是很精确,如果不能很精确地估计出来,输出"Bad Estimations"

    Sample Input:

    3 2
    1000 2000 1000
    1 2 1100
    2 3 1300

    Sample Output:

    1300

    思路:

    如果不了解差分约束系统,请点传送门

    数学模型为:设3个军营的人数分别为A1, A2, A3,容量为C1, C2, C3,前n个军营的总人数为Sn,则有:

    1. 则根据第i个大营到第j个大营士兵总数至少有k个,得不等式组(1):
    S2 – S0 >= 1100 等价于 S0 – S2 <= -1100
    S3 – S1 >= 1300 等价于 S1 – S3 <= -1300

    2. 每个兵营实际人数不超过容量,得不等式组(2)
    A1 <= 1000 等价于 S1 – S0 <= 1000
    A2 <= 2000 等价于 S2 – S1 <= 2000
    A3 <= 1000 等价于 S3 – S2 <= 1000

    3. 另外由Ai>=0,又得到不等式组(3)
    S0 – S1 <= 0
    S1 – S2 <= 0
    S2 – S3 <= 0

    注:书上还表标明一组不等式:

    又根据实际情况,第i个大营到第j个大营的士兵总数不超过这些兵营容量之和,设d[i]为前i个大营容量总和,得不等式组(4):
    S2 – S0 <= d[2] – d[0] = 3000
    S3 – S1 <= d[3] – d[1] = 3000

    但这组不等式是多余的,这是由于每两个相邻的点之间都有了两条边,这组不等式就是它的传递闭包中的某些边,但是在进行bellman算法的时候,已经进行松弛,在迭代的过程已经考虑了这些边,所以是多余的。

    比如上面这个例子,上面的不等式组4完全可以通过不等式组2相加得到,所以加入这些边是没有意义的。

    由上述不等式组,就可以建出图中需要的边。答案需要求总人数的最小值,就是A1+A2+A3的最小值(即S3 – S0的最小值)

    要求S3 – S0的最小值,即要求不等式:
    S3 – S0 >= M中的M的最大值(M没有最小值,最小可以是负无穷),转化成:S0 – S3 <= -M(-M的最小值,也就是求S3到S0的最短路径),长度为-M

    所以对于Sn来说,求的是从Sn到S0的最短路径,所以源点是Sn,总点数有n+1个,所以用Bellman算法需要迭代n次才能求出最短路,并且还需要迭代第n+1次判断负环是否存在(写题目的时候就是只迭代n次导致一直出错)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #include<stack>
     8 #include<map>
     9 #include<set>
    10 #include<sstream>
    11 #define MEM(a, b) memset(a, b, sizeof(a));
    12 using namespace std;
    13 typedef long long ll;
    14 const int maxn = 1000 + 10;
    15 const int maxm = 1e5;
    16 const int INF = 9999999;
    17 int n, m, tot;
    18 int d[maxn];//最短路径
    19 struct edge
    20 {
    21     int u, v, w;
    22     edge(int u, int v, int w):u(u), v(v), w(w){}
    23     edge(){}
    24 };
    25 edge e[maxm];
    26 void addedge(int u, int v, int w)
    27 {
    28     e[tot++] = edge(u, v, w);
    29 }
    30 bool bellman(int u)
    31 {
    32     for(int i = 0; i <= n; i++)d[i] = INF;
    33     d[u] = 0;
    34     for(int i = 0; i <= n; i++)//迭代n + 1次,因为有n+1个点,普通迭代需要n次,第n+1次迭代是为了检查有无负环
    35     {
    36         for(int j = 0; j < tot; j++)
    37         {
    38             int u = e[j].u, v = e[j].v, w = e[j].w;
    39             if(d[u] < INF && d[v] > d[u] + w)
    40             {
    41                 d[v] = d[u] + w;
    42                 if(i == n)return true;
    43             }
    44         }
    45     }
    46     return false;
    47 }
    48 int main()
    49 {
    50     while(cin >> n >> m)
    51     {
    52         tot = 0;
    53         int x;
    54         for(int i = 1; i <= n; i++)
    55         {
    56             scanf("%d", &x);
    57             addedge(i - 1, i, x);
    58             addedge(i, i - 1, 0);
    59         }
    60         int u, v, w;
    61         for(int i = 0; i < m; i++)
    62         {
    63             scanf("%d%d%d", &u, &v ,&w);//Sv - Su-1 >= w   ==>   Su-1 - Sv <= -w   ==>   建立边<v, u-1>权值为-w
    64             addedge(v, u-1, -w);
    65         }
    66         if(bellman(n))cout<<"Bad Estimations"<<endl;
    67         else cout<<(-d[0])<<endl;
    68     }
    69     return 0;
    70 }
  • 相关阅读:
    路由系统
    flask_sqlalchemy的使用
    input()输入语句
    注释
    Python 2017.1.5
    关于object网页播放器参数的设置,推荐博客系列
    LRU缓存,大神写的,值得借鉴
    object,网页播放器的相关属性设置
    js的apply和call方法
    count()函数在count()中参数的讨论
  • 原文地址:https://www.cnblogs.com/fzl194/p/8734282.html
Copyright © 2011-2022 走看看