POJ 1201 Intervals (差分约束,最短路)

题意:假设有一个自然数区间[0,50000],要从中挑出一些自然数出来,但是现在不知道整个区间究竟要挑多少个出来,只知道一部分闭区间[a,b]内至少要挑多少个,所知道的有n个闭区间。问至少要挑出多少个?

思路:

  对于所给的区间 cnt[b-a]>=k这可以保证了该区间内个数不少于k。但是由于两边都是闭区间,所以要变cnt[b-(a-1)]>=k,表示b到a之间的个数。也就是说,转成式子是b-(a-1)>=k,变换一下为(a-1)-b<=-k,就满足常见的式子b-a<=k啦,可以建边b指向(a-1),权值为-k。

  但是还有没有其他的约束条件呢?如果我们只是这样建图,那很多个点都不会有联系的啊,比如[3,7]>=2和 [5,9]>=4,建边为2->7和4>9,完全不搭边啊!肯定还有其他联系,相邻的两个数字之间是否可以有边?可以的,至少可以满足a-(a-1)>=0吧?表示a只能被选与不被选。还有呢?每个点最多只能被选一次吧?则有a-(a-1)<=1。

  综合3条式子,可以变形得到:

  (1)(a-1)-b<=-k

  (2)(a-1)-a<=0

  (3)a-(a-1)<=1

  都满足了常见的式子。那么可以建边了。这下每两个相邻数字就起码有两条边。

  我们要求的是什么?满足要求的,整个区间所挑的最小个数。从最大数字出发,进行求最短路后,最小的数的那个点通常就会得到一个负权路径和啦,cost[最小]=负值。而cost[最小]取相反数就是答案了。记得开始前要将cost[起点]置为0。大概思路是这样,但是区间是[0,50000],所以0-1时还会出现负数下标,可以将整个区间右移一位变成[1,50001]。

 1 //#include <bits/stdc++.h>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <map>
 5 #include <iostream>
 6 #include <deque>
 7 #include <vector>
 8 #define INF 0x7f7f7f7f
 9 #define pii pair<int,int>
10 #define LL unsigned long long
11 using namespace std;
12 const int N=51010;
13 struct node
14 {
15     int from,to,cost;
16     node(){};
17     node(int from,int to,int cost):from(from),to(to),cost(cost){};
18 }edge[N*4];
19 vector<int> vect[N];
20 int edge_cnt;
21
22 void add_node(int from,int to,int cost)
23 {
24     edge[edge_cnt]=node(from,to,cost);
25     vect[from].push_back(edge_cnt++);
26 }
27
28 bool inq[N];
29 int cost[N];
30 int spfa(int small,int big)
31 {
32     memset(inq,  0, sizeof(inq));
33     memset(cost, 0x7f, sizeof(cost));
34     cost[big]=0;
35     deque<int> que(1,big);
36
37     while(!que.empty())
38     {
39         int x=que.front();que.pop_front();
40         inq[x]=0;
41
42         for(int i=0; i<vect[x].size(); i++)
43         {
44             node e=edge[vect[x][i]];
45             if(cost[e.to]>cost[x]+e.cost)
46             {
47                 cost[e.to]=cost[x]+e.cost;
48                 if(!inq[e.to])
49                 {
50                     inq[e.to]=1;
51                     if(!que.empty() && cost[e.to]<cost[que.front()])    que.push_front(e.to);
52                     else    que.push_back(e.to);
53                 }
54             }
55         }
56     }
57     return -cost[small];
58 }
59
60 int main()
61 {
62     //freopen("input.txt", "r", stdin);
63     int n, m, a, b, c;
64     while(~scanf("%d",&n))
65     {
66         edge_cnt=0;
67         memset(edge,0,sizeof(edge));
68         for(int i=0; i<N; i++)  vect[i].clear();
69         int small=INF, big=0;
70
71         for(int i=0; i<n; i++)
72         {
73             scanf("%d%d%d",&a,&b,&c);
74             add_node(b+1,a,-c);   //右移了1位
75
76             small=min(small, a+1);
77             big=max(big, b+1);
78         }
79         //每两个点之间的
80         for(int i=small; i<=big; i++)
81         {
82             add_node(i-1, i, 1);
83             add_node(i, i-1, 0);
84         }
85         cout<<spfa(small-1, big)<<endl;
86     }
87     return 0;
88 }

AC代码

时间: 2024-10-31 22:11:14

POJ 1201 Intervals (差分约束,最短路)的相关文章

POJ 1201 Intervals 差分约束

http://poj.org/problem?id=1201 TLE了很久,因为用了cin..... 思路和其他差分约束差不多,http://www.cppblog.com/menjitianya/archive/2015/11/19/212292.html 如果区间[a, b]中至少有c个元素,如果用上面的博客,那么说明xa - xb >= c,但是注意这里是闭区间,xa - xb是不包括b这个点的, 就比如用了[a, b]有c个元素,[b, d]有x个,那么ans = c + x - 1个,

POJ 2101 Intervals 差分约束

Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 27746   Accepted: 10687 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

poj 1201 Intervals 差分约束系统

题目链接:http://poj.org/problem?id=1201 题意:给定n(1<= n <= 50000)个 闭区间,每个区间后面带一个值 Ci, 问集合Z个数的最小值使得在每个区间中的数的个数 “不少于Ci”? 思路: S[i] 表示 小于等于i 的个数,这样可以直接按照输入建立不等式之后转化为有向网即可: 需要注意的是 在原始的两个不等式 S[i-1] - s[i] <= 0 和 s[i-1] - s[i] <= 1不宜在建边时就加入,这会使得有向网络中的边数达到3*

poj 1201 Intervals(差分约束系统)(困难)

Intervals Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 23205   Accepted: 8764 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 po

POJ 1201 Intervals(图论-差分约束)

Intervals Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 20779   Accepted: 7863 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 po

POJ 3169 Layout (差分约束+SPFA)

Layout Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6832   Accepted: 3292 Description Like everyone else, cows like to stand close to their friends when queuing for feed. FJ has N (2 <= N <= 1,000) cows numbered 1..N standing along a

POJ 1364 King --差分约束第一题

题意:求给定的一组不等式是否有解,不等式要么是:SUM(Xi) (a<=i<=b) > k (1) 要么是 SUM(Xi) (a<=i<=b) < k (2) 分析:典型差分约束题,变换,令Ti = SUM(Xj) (0<=j<=i).  则表达式(1)可以看做T(a+b)-T(a-1) > k,也就是T(a-1)-T(a+b) < -k,又因为全是整数,所以T(a-1)-T(a+b) <= -k-1.  同理,(2)看做T(a+b)-T(

POJ 1364 King 差分约束 找负环

嘛,虽然是一道水题+模板题,不过还是学到了很多东西的,记录一下. 首先题目给出的不等式是小于,但是差分约束系统只能处理小于等于的情况,所以要转化成小于等于的进行处理.对于整数处理方法非常简单= = 然后是找负环的情况,其实不需要考虑图连不连通,只要一开始就把所有的点的d置成0,然后都push进队列里面就好了. PS:这种方法同样可以用在处理多源点最短路问题上. #include <cstdio> #include <cstring> #include <cmath> #

poj 1201 Intervals【差分约束+spfa】

设s为前缀和,首先显然的条件是\[ s_{bi}-s_{ai-1}>=c \],然后隐含的是\[ s_i-s_{i-1}>=0 s_i-s_{i-1}<=1 \] 然后根据差分约束,就是连边(bi,ai-1,-li),(i-1,i,1),(i,i-1,0) spfa跑最长路最后输出相反数即可,注意n是起点,min是终点,跑最短路(不会有负环) #include<iostream> #include<cstdio> #include<queue> usi

POJ 1201 Intervals(差分约束 区间约束模版)

关于差分约束详情可阅读:http://www.cppblog.com/menjitianya/archive/2015/11/19/212292.html 题意: 给定n个区间[L,R], 每个区间至少放w个球, 问最后整个区间最少要放多少个球. 分析: 假设d[i] 是 [1,i] 至少有多少个点被选中, 特殊地, d[0] = 0. 每个区间的描述可以转化为d[R] - d[L-1] >= w.(因为d[L]也要选中, 左闭右闭区间, 所以要减d[L-1])因为d[i]描述了一个求和函数,所