解题报告 之 POJ1201 Intervals

解题报告 之 POJ1201 Intervals


  
      Description
You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn. 
Write a program that: 
reads the number of intervals, their end points and integers c1, ..., cn from the standard input, 
computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i=1,2,...,n, 
writes the answer to the standard output. 

Input

The first line of the input contains an integer n (1 <= n <= 50000) -- the number of intervals. The following n lines describe the intervals. The (i+1)-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50000 and 1 <= ci <= bi - ai+1.

Output

The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each i=1,2,...,n.

Sample Input

53 7 38 10 36 8 11 3 110 11 1

Sample Output

6

    我不得不说一开始没读懂题。。。后来终于懂了。。。
    题目大意:给N个闭区间,对每个[ai,bi] 任意取ci个数,最终将取出来的数组成一个集合S,根据互异性,求S中最少有几个元素。这道题乍一看觉得比较变态。。。根据提示学习了一下差分约束系统。差分约束系统主要用于解决求解多个约束不等式下的解的问题。系统中,有n个变量,m个约束。约束形如
xj-xi<=bk,于是乎就可以联想到最短路中的d[v]-d[u]<=w[u,v]。系统的要么无解要么有无数组解,所以我们可以通过Bellmen-Ford算法或者是SPFA算法来求得一组解。
     
关于初始化dis的问题:

    1.如果将源点到各点的距离初始化为0,最终求出的最短路满足 它们之间相互最接近了。
    2.如果将源点到各点的距离初始化为INF(无穷大),其中之1为0,最终求出的最短路满足 它们与该点之间相互差值最大。

    于是乎这道题的话就是用dis[i]表示到i之前一共选了几个。于是乎得到约束方程dis[bi]-dis[ai]>=ci;还有两个隐讳的约束,就是dis[i+1]-dis[i]<=1已经dis[i+1]-dis[i]>=0 .
                                             约束条件标准形式  : 
dis[ai]<=dis[bi]-ci;
                                                                           
dis[i+1]-dis[i]<=1;
                                                                           dis[i]-dis[i+1]<=0; 
 
   所以用Bellmen-Ford算法每次更新三个约束的值,直到不更新为止。(此题不会出现负权回路的情况所以无需担心),最后答案就是d[max-bi]-d[min-ai] , 所以d[i]的初始值不重要,到最后都会剪掉。

#include<iostream>

#include<algorithm>

using namespace std;

#define MAXN 50010

#define INF 1000000

 

struct edge

{

      int u, v, w;

};

 

edge edges[MAXN];

 

int n, dis[MAXN], ms, me;

 

void bellmen_ford()

{

      bool flag=true;

      while (flag)

      {

            flag = false;

 

            for (int i = 1; i <= n; i++)

            {

                  if (dis[edges[i].u] > dis[edges[i].v] - edges[i].w)

                  {

                        dis[edges[i].u] = dis[edges[i].v] - edges[i].w;

                        flag = true;     

                  }

            }

 

            for (int i = ms; i <= me; i++)

            {

                  if (dis[i] > dis[i - 1] + 1)

                  {

                        dis[i] = dis[i - 1] + 1;

                        flag = true;

                  }

            }

 

            for (int i = me; i >= ms; i--)

            {

                  if (dis[i - 1] > dis[i])

                  {

                        dis[i - 1] = dis[i];

                        flag = true;

                  }

            }

      }

}

 

int main()

{

      while (scanf("%d", &n) == 1)

      {

            ms = INF;

            me = -1;

            for (int i = 1; i <= n; i++)

            {

                  scanf("%d %d %d", &edges[i].u, &edges[i].v, &edges[i].w);

                  ms = min(ms, edges[i].u);

                  me = max(me, edges[i].v);

                  dis[i] = i;

                  edges[i].u--;

            }

            bellmen_ford();

            printf("%d\n", dis[me] - dis[ms - 1]);

      }

      return 0;

}

感觉是很久以前的题了,于是还是写上来了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值