An integer interval [a,b], a < b, is a set of all consecutive integers beginning with a and ending with b.
Write a program that: finds the minimal number of elements in a set containing at least two different integers from each interval.
Input
The first line of the input contains the number of intervals n, 1 <= n <= 10000. Each of the following n lines contains two integers a, b separated by a single space, 0 <= a < b <= 10000. They are the beginning and the end of an interval.
Output
Output the minimal number of elements in a set containing at least two different integers from each interval.
Sample Input
4 3 6 2 4 0 2 4 7
Sample Output
4
来源参考博客:
https://blog.csdn.net/my_sunshine26/article/details/72849593
https://blog.csdn.net/linyuxilu/article/details/51954030
题意:给出数轴上的n个闭合int型区间。现在要在数轴上任意取一堆元素,构成一个元素集合V,要求给出的每个区间和元素集合V的交集至少有两个不同的元素,求集合V最小的元素个数。
思路:(1)贪心
(2)差分约束:
先推荐这篇SPFA详解(含图解+过程模拟+模板例题):
http://keyblog.cn/article-21.html~
http://keyblog.cn/article-21.html~
http://keyblog.cn/article-21.html~
(1)贪心
先对所有区间按末端点排序
取第i个区间的最后两个元素x和y
元素个数初值初始化为2
x初始化为第一个区间的最后倒数第2个元素
y初始化为第一个区间的最后的元素
若第i+1个区间包含了这两个元素,则跳到下一个区间,所取的元素个数+0
若第i+1个区间只包含了这两个元素中的一个(由于有序,所以必定是包含y),则取第i+1个区间的最后一个元素,所取的元素个数+1。为了方便下一区间的比较,更新x和y的值,使他们为当前V集合中最后的两个元素。
若第i+1个区间没有包含这两个元素,则第i+1个区间的最后两个元素,所取的元素个数+2。为了方便下一区间的比较,更新x和y的值,使他们为当前V集合中最后的两个元素。
#include<stdio.h>
#include<algorithm>
using namespace std;
struct F
{
int a,b;
} s[10010];
int cmp(F x,F y)
{
return x.b<y.b;
}
int main()
{
int n,i,j,x,y;
scanf("%d",&n);
for(i=0; i<n; i++)
scanf("%d%d",&s[i].a,&s[i].b);
sort(s,s+n,cmp);
j=2;
x=s[0].b-1;
y=s[0].b;
for(i=1; i<n; i++)
{
if(s[i].a<=x&&s[i].b>=y)//如果此区间包含了这两个元素,不用再取
continue;
if(s[i].a<=y&&s[i].a>x)//如果只包含一个,肯定是y
{
x=y;
y=s[i].b;//更新x和y
j+=1;//增加一个元素
}
if(s[i].a>y)//如果不包含任意一个元素,就需要增加后两位元素
{
x=s[i].b-1;//更新元素的值
y=s[i].b;//因为数据是从小到大排的额,所以保存后两位
j+=2;//元素数量加2
}
}
printf("%d\n",j);
return 0;
}
(2)差分约束
对于差分约束,我们可以这样考虑,令sum[x]为[0,x]内所在集合V中元素个数,
那么我们就能很容易得到:对于每个区间【a,b】,sum[b+1]-sum[a]>=2。
但千万不能忘了隐含的约束条件:0<=sum[i+1]-sum[i]<=1.
综上所述:不等数组统一化为:sum[b+1]-sum[a]>= 2 建边:add(a,b+1,2)
sum[i+1]-sum[i]>= 0 建边:add(i,i+1,0)
sum[i]-sum[i+1]>= -1 建边:add(i+1,i,-1)
建边完毕后跑个最长路即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
const int maxn=10005;
const int INF =0x3f3f3f3f;
const double eps =1e-6;
using namespace std;
int dist[maxn],visit[maxn],nums[maxn],head[maxn];
int n,cnt;
struct Node
{
int v,w,next;
}edge[maxn*3];
void add(int u,int v,int w)
{
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void init()
{
cnt=0;
memset(head,-1,sizeof(head));
}
int spfa(int s,int t)
{
memset(visit,0,sizeof(visit));
memset(nums,0,sizeof(nums));
for(int i=0;i<=t;i++)
{
dist[i]=-INF;
}
queue<int>q;
visit[s]=1;
dist[s]=0;
nums[s]++;
q.push(s);
while(q.size())
{
int now=q.front();
q.pop();
visit[now]=0;
for(int i=head[now];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
int w=edge[i].w;
if(dist[v]<dist[now]+w)
{
dist[v]=dist[now]+w;
if(!visit[v])
{
q.push(v);
visit[v]=1;
}
}
}
}
return dist[t];
}
int main()
{
int a,b;
while(~scanf("%d",&n))
{
init();
int maxx=0;
for(int i=0;i<n;i++)
{
scanf("%d%d",&a,&b);
add(a,b+1,2);
maxx=max(maxx,b+1);
}
for(int i=0;i<=maxx;i++)
{
add(i,i+1,0);
add(i+1,i,-1);
}
int ans=spfa(0,maxx);
printf("%d\n",ans);
}
return 0;
}