POJ 1716 Integer Intervals(贪心or差分约束)
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
题意
有一段数,1~N,让你从这N个数中选择ans个。输入N个区间,要求满足每个区间至少包含2个被选择的数。输出最小ans。
思路
有两种做法
一、因为只要满足在给出的N个区间内都要选择两个数,所以可以尽量在两个区间有交集的部分选择数,比如【1,4】和【2,3】,只要选择2、3两个数,就能满足两个区间都有两个数。
所以可以对区间右端点排序,贪心即可。每次可以尽量选区间右端点的两个数,这样可以尽量使后面的区间也尽量包含已经选了的数。
二、差分约束
设a[i]为从起点到第i个点选择了多少个数
所以对于输入的区间【left,right】有a[right]-a[left-1]>=2
因为left>=0,为了方便处理负数,可以左右端点统一 +1,上式等价a[right+1]-a[left]>=2
但是只有N个区间给出的关系还是不能建图
所以还有以下隐含关系
a[i+1]-a[i]>=0
a[i+1]=a[i]<=1
之后就可以建图,跑一边最短路 spfa 即可
通过上面三个关系,可以如下方式具体建边(单向边)
right+1,left,-2
i,i+1,1
i+1,i,0
思路一
AC代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define maxn 10010
#define maxm 210
typedef struct node{
int l,r;
}node;
node a[maxn];
bool cmp(node a,node b) //按右端点排序
{
return a.r<b.r;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF){
int i;
for(i=0;i<n;i++){
scanf("%d%d",&a[i].l,&a[i].r);
}
sort(a,a+n,cmp);
int ans=2; //答案
int x=a[0].r-1,y=a[0].r; //起始选好了两个点
for(i=1;i<n;i++){
//如果已经选的点有两个点在当区间,则不需要继续选新点
if(a[i].r>=y&&a[i].l<=x){
continue;
}
//如果已经选的点都在当前区间左端点之前,则需要选两个新点
if(a[i].l>y){
x=a[i].r-1; //贪心可知,每次选区间右端点的两个点最优
y=a[i].r;
ans+=2;
}
else{ //上面两个if外的情况就是只包含了一个点,所以此时再选择一个右端点即可
x=y;
y=a[i].r;
ans++;
}
}
printf("%d\n",ans);
}
return 0;
}
思路二
AC代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define maxn 10010
#define maxm 210
int tot,ma,mi;
int head[maxn],dis[maxn];
bool vis[maxn];
typedef struct node{
int v,nex,w;
}node;
node e[maxn+maxn+maxn]; //要开三倍的N,否则可能会RT
void add(int u,int v,int w) //建边
{
e[tot].v=v;
e[tot].w=w;
e[tot].nex=head[u];
head[u]=tot++;
}
void spfa()
{
//printf("ans:\n");
for(int i=0;i<ma;i++){ //初始化
dis[i]=inf;
vis[i]=0;
}
dis[ma]=0;
queue<int>q;
q.push(ma);
while(!q.empty()){
int v,u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=e[i].nex){
v=e[i].v;
if(dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
if(!vis[v]){
q.push(v);
vis[v]=true;
}
}
}
}
printf("%d\n",abs(dis[mi]-dis[ma]));
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF){
tot=0;
mi=inf;
ma=-inf;
memset(head,-1,sizeof(head));
int i,l,r;
for(i=0;i<n;i++){
scanf("%d%d",&l,&r);
mi=min(mi,l);
ma=max(ma,r+1);
add(r+1,l,-2);
}
for(i=0;i<ma;i++){
add(i,i+1,1);
add(i+1,i,0);
}
spfa();
}
return 0;
}