• POJ-1201 Intervals---差分约束


    题目链接:

    https://vjudge.net/problem/POJ-1201

    题目大意:

    一个整数集合Z有n个区间,每个区间有3个值,ai,bi,ci代表,在区间[ai,bi]上至少有ci个整数属于集合Z,ci可以在区间内任意取不重复的点。
    现在要满足所有区间的约束条件,问最少可选多少个点。

    Sample Input

    5
    3 7 3
    8 10 3
    6 8 1
    1 3 1
    10 11 1

    Sample Output

    6

    思路:

    求最小的整数集合Z满足| Z ∩ [ ai,  bi ] | >= ci。意思就是在区间[ai,bi]上至少有ci个整数属于集合Z。

    可以建模成一个差分约束系统。以输入的测试数据为例进行分析:

    设S[i]是集合Z中小于等于i的元素个数。那么就有以下不等式组:

    (1)Z集合中范围在[ai, bi]的整数个数至少为ci,也就相当于S[bi] - S[ai - 1] >= ci

      根据差分约束系统中的三角不等式(d[v] - d[u] <=  Edge[u][v])

      上述不等式可以转化成S[ai - 1] - S[bi] <= -ci      边:<bi, ai-1> 权值-ci

        上述例子就有以下不等式组(1)

      S2 - S7 <= -3

      S7 - S10 <= -3

      S5 - S8 <= -1

      S0 - S3 <= -1

      S9 - S11 <= -1

    (2)根据实际情况,还有两个约束条件

      S[i] - S[i - 1] <= 1

      S[i] - S[i - 1] >= 0,即S[i - 1] - S[i] <= 0

    最终要求的是什么?

    设所有区间右端点的最大值为mx,如该测试数据中mx = 11, 所有区间左端点的最小值为mn

    如该测试数据中mn = 1, mn - 1 = 0

    最终要求的是S[mx] - S[mn - 1]的最小值,也就是S[mx] - S[mn - 1] >= M(M的最大值)

    也就是S[mn - 1] - S[mx] <= -M(-M的最小值)也就是点mx到点mn-1的最短路-M,答案求的是M

    这里需要注意的是源点是mx,终点是mn-1。

    所以进行bellman算法时,应该从mx出发,求出dist[mn - 1]。(dist数组保存的是从源点出发到各点的最短距离)

    但是上述的约束条件太多,最多会达到3*50000条边,全部转化成边不是个好方法,所以应该进行优化:

      (1)用上述不等式组(1)进行建图,源点到各个顶点最短路径初始为0,因为Si - Smx <=0,所以源点到各个顶点的距离一定会小于等于0,

      (2)用Bellman算法求出源点到各个顶点的最短路径长度,每次循环时,判断完约束条件(1)后,再判断约束条件(2)和(3)

      约束条件(2)的判断

      S[i] - S[i - 1] <= 1等效于S[i] - S[mx] <= S[i - 1] - S[mx] + 1

      由于上述dist数组表示从源点出发到各点的最短距离,所以S[i] - S[mx]就是dist[i]

      上述条件转化成了dist[i] <= dist[i - 1] + 1

      如果dist[i] > dist[i - 1] + 1, 那么修改dist[i] = dist[i - 1] + 1。

      约束条件(3)的判断

      S[i - 1] <= S[i] 等效于S[i - 1] - S[mx] <= S[i] - S[mx] 

      也就是dist[i - 1] <= dist[i]

      如果dist[i - 1] > dist[i] 那就修改dist[i- 1] = dist[i]

     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 = 50000 + 10;
    15 const int INF = 0x3f3f3f3f;
    16 int T, n, m, cases, tot;
    17 int d[maxn];
    18 struct edge
    19 {
    20     int u, v, w;
    21     edge(){}
    22     edge(int u, int v, int w):u(u), v(v), w(w){}
    23 };
    24 edge a[maxn];
    25 int mx, mn;//mn左区间最小值,mx右区间最大值
    26 void init()
    27 {
    28     tot = 0;
    29     MEM(d, 0)//初始化源点0到各个顶点的距离,这里的d[mx]永远是0,这就是源点
    30     mx = 1, mn = INF;
    31 }
    32 void bellman()
    33 {
    34     bool update = 1;
    35     while(update)//如果有不更新的时候,直接退出
    36     {
    37         update = 0;
    38         for(int i = 0; i < n; i++)//Bellman算法的边循环
    39         {
    40             int u = a[i].u, v = a[i].v, w = a[i].w;
    41             if(d[v] > d[u] + w)
    42             {
    43                 update = 1;
    44                 d[v] = d[u] + w;
    45             }
    46         }
    47 
    48         //约束条件2的判断
    49         for(int i = mn; i <= mx; i++)
    50         {
    51             if(d[i] > d[i - 1] + 1)
    52             {
    53                 update = 1;
    54                 d[i] = d[i - 1] + 1;
    55             }
    56         }
    57 
    58         //约束条件3的判断
    59         for(int i = mx; i >= mn; i--)
    60         {
    61             if(d[i - 1] > d[i])
    62             {
    63                 update = 1;
    64                 d[i - 1] = d[i];
    65             }
    66         }
    67     }
    68 }
    69 int main()
    70 {
    71     while(cin >> n)
    72     {
    73         init();
    74         int u, v, w;
    75         for(int i = 0; i < n; i++)
    76         {
    77             scanf("%d%d%d", &u, &v, &w);
    78             a[i] = edge(v, u - 1, -w);//建边
    79             mx = max(mx, v);
    80             mn = min(mn, u);
    81         }
    82         //cout<<mx<<" "<<mn<<endl;
    83         bellman();
    84         printf("%d
    ", -d[mn - 1]);
    85     }
    86     return 0;
    87 }
  • 相关阅读:
    ASP.NET CORE3.0 API Swagger+IdentityServer4授权验证
    Ubuntu16.04安装RabbitMq并设置用户
    使用sql实现表90度旋转(矩阵转置)
    HDWiKi新架设网站打开慢原因排查1.4秒→0.03秒
    手机端网页设置了csswidth:100%,但不能显示完整的问题
    SQL Server 2008 收缩日志
    MSSQL查看一个数据库中所有表的行数
    那就简单说说这个服务器吧,题外话。
    win7单独安装php
    css兼容写法
  • 原文地址:https://www.cnblogs.com/fzl194/p/8734451.html
Copyright © 2020-2023  润新知