zoukankan      html  css  js  c++  java
  • SP116 INTERVAL

    题意翻译

    区间取数

    题目描述

    有n个区间,在区间[ai,bi]中至少取任意互不相同的ci个整数。求在满足n个区间的情况下,至少要取多少个正整数。

    输入输出格式

    输入格式

    多组数据。

    第一行的一个整数T表示数据个数。对于每组数据,第一行包含一个整数n(1<=n<=50000)表示区间数。以下n行描述区间。输入的第(i+1)行包含三个整数ai,bi,ci,由空格分开。其中0<=ai<=bi<=50000,1<=ci<=bi-ai+1。

    输出格式

    对于每组数据,输出一个对于n个区间[ai,bi] 至少取ci个不同整数的数的总个数。

    输入输出样例

    输入样例#1:

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

    输出样例#1:

    6

    解析:
    这是一道差分约束的模板题,写完这一题之后可以更好地理解差分约束。


    【差分约束系统】
    差分约束系统是一种特殊的N元一次不等式组。它包含N个变量X1~XN以及M个约束条件,每个约束条件都是由两个变量作差构成的,形如Xi-Xj<=ck,其中ck是常数。我们要解决的问题是:求X的一组解,使得所有约束条件得到满足。

    实际上,最短路径问题和最长路径问题都是某种程度上的差分约束系统,对于差分约束系统中的每个条件Xi-Xj>=ck我们可以变形为Xi<=Xj+ck。而单源最短/长路实际上是求了一个差分约束系统的最优解(最小/大的符合条件的情况)。
    也就是说,对于一个无向图,我们得到的所有可达点之间的每一条简单路径,都是这个“路径”的差分约束系统的一组解(这个系统几乎没有约束条件)。如果我们要求某一个差分约束系统的最优解,就相当于在一张图上求解最短/长路。

    为了便于理解,我们可以将求解最短/长路径的方法看做是求解差分约束的一种工具,将差分约束系统的条件变形作三角形不等式进行求解。


    我们看回这道题目,我们会发现题意与差分约束系统十分相似。
    假设s[k]为0~k之间最少取到的互不相同(隐藏条件)的整数,根据题意,我们容易得到s[bi]-s[ai-1]>=ci。
    特别的,差分约束系统的题目总是有一些隐藏条件,这些条件我们也必须加入到差分约束系统中去,使得这些条件也成立。
    本题中,隐藏条件有:
    1. 对于任意一个数,要不然选一次,要不然不选, 不能选两次。于是得到:s[k]-s[k-1]<=1
    2. 对于任意一个区间0~k-1,必然存在一个区间0~k选出的数要不然比0~k-1多,要不然选出的数一样多。于是得到:s[k]-s[k-1]>=0。

    但是我们尴尬的发现他们不等号的方向不一致,没事,我们转化一下就好了。

    条件1可以变为s[k-1]-s[k]>=-1。

    注意一个问题:

    如果Xi-Xj的约束条件是<=号,则我们要求的是最短路;

    如果约束条件是>=号,则我们要求的是最长路(根据三角形不等式得出)。


    首先,我们把0~k(此处的k为最大的那个bi)按照隐藏约束条件初始化,也就是,从每个k-1连一条长0的有向边至k,从每个k连一条长-1的边至k-1。

     

    然后按照输入,依次加入ai-1 -> bi的长度为ci的有向边。

     

    值得注意的是,这里数组下标不能为负数,那我们就给他加成正的,以0为初始阶段点开始,求最长路。

    最优解便是d[k]了。

     

    参考代码:(话说这道题快读会爆?!)

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<queue>
     6 #include<algorithm>
     7 #define N 100010
     8 using namespace std;
     9 queue<int> q;
    10 struct node{
    11     int next,ver,edge;
    12 }g[N<<1];
    13 int head[N],tot,d[N],n;
    14 bool v[N<<1];
    15 void add(int x,int y,int val)
    16 {
    17     g[++tot].ver=y,g[tot].edge=val;
    18     g[tot].next=head[x],head[x]=tot;
    19 }
    20 void spfa(int x)
    21 {
    22     memset(d,-1,sizeof(d));
    23     memset(v,0,sizeof(v));
    24     d[x]=0;v[x]=1;
    25     q.push(x);
    26     while(q.size())
    27     {
    28         int index=q.front();q.pop();
    29         v[index]=0;
    30         for(int i=head[index];i;i=g[i].next){
    31             int y=g[i].ver,z=g[i].edge;
    32             if(d[y]<d[index]+z){
    33                 d[y]=d[index]+z;
    34                 if(!v[y]) v[y]=1,q.push(y);
    35             }
    36         }
    37     }
    38 }
    39 int main()
    40 {
    41     int t;
    42     cin>>t;
    43     for(int k=1;k<=t;k++)
    44     {
    45         tot=0;
    46         memset(g,0,sizeof(g));
    47         memset(head,0,sizeof(head));
    48         int cnt=-N;
    49         scanf("%d",&n);
    50         
    51         for(int i=1;i<=n;i++)
    52         {
    53             int x,y,c;
    54             scanf("%d%d%d",&x,&y,&c);
    55             add(x,y+1,c);
    56             cnt=max(cnt,y);
    57         }
    58         for(int i=1;i<=cnt+1;i++){
    59             add(i-1,i,0),add(i,i-1,-1);
    60         }
    61         spfa(0);
    62         if(k<t) printf("%d
    ",d[cnt+1]);
    63         else printf("%d",d[cnt+1]);
    64     }
    65     return 0;
    66 }

     

  • 相关阅读:
    Java自学二十六天
    Java自学三十四天
    Java自学三十二天
    Java自学三十天
    Java开学考试心得
    Java自学二十九天
    Java自学二十八天
    Java自学三十一天
    Java自学三十三天
    2020年月12日Java学习日记
  • 原文地址:https://www.cnblogs.com/DarkValkyrie/p/11022797.html
Copyright © 2011-2022 走看看