题目描述 Description
给定x轴上的N(0 < N<100)条线段,每个线段由它的二个端点a_I和b_I确定,I=1,2,……N.这些坐标都是区间(-999,999)的整数。有些线段之间会相互交叠或覆盖。请你编写一个程序,从给出的线段中去掉尽量少的线段,使得剩下的线段两两之间没有内部公共点。所谓的内部公共点是指一个点同时属于两条线段且至少在其中一条线段的内部(即除去端点的部分)。
输入描述 Input Description
输入第一行是一个整数N。接下来有N行,每行有二个空格隔开的整数,表示一条线段的二个端点的坐标。
输出描述 Output Description
输出第一行是一个整数表示最多剩下的线段数。
样例输入 Sample Input
3
6 3
1 3
2 5
样例输出 Sample Output
2
数据范围及提示 Data Size & Hint
0< N<1 00
思路:贪心,先按右端点从小到大排序,右端点相同的按左端点从大到小排序。
题解:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct cc{
int x,y;
}a[105];
int cmp(cc a,cc b)
{
if(a.y==b.y)
{
return a.x>b.x;
}
return a.y<b.y;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>a[i].x>>a[i].y;
if(a[i].x>a[i].y)
{
swap(a[i].x,a[i].y);
}
}
sort(a+1,a+n+1,cmp);
int last=-21478364;
int ans=0;
for(int i=1;i<=n;i++)
{
if(a[i].x>=last)
{
ans++;
last=a[i].y;
}
}
printf("%d",ans);
return 0;
}
——————————————————-华丽的分割线———————————————————-
题目描述 Description
数轴上有n条线段,线段的两端都是整数坐标,坐标范围在0~1000000,每条线段有一个价值,请从n条线段中挑出若干条线段,使得这些线段两两不覆盖(端点可以重合)且线段价值之和最大。
n<=1000
输入描述 Input Description
第一行一个整数n,表示有多少条线段。
接下来n行每行三个整数, ai bi ci,分别代表第i条线段的左端点ai,右端点bi(保证左端点<右端点)和价值ci。
输出描述 Output Description
输出能够获得的最大价值
样例输入 Sample Input
3
1 2 1
2 3 2
1 3 4
样例输出 Sample Output
4
数据范围及提示 Data Size & Hint
数据范围
对于40%的数据,n≤10;
对于100%的数据,n≤1000;
0<=ai,bi<=1000000
0<=ci<=1000000
思路:DP思想,最长上升子序列。
题解:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct cc{
int x,y,cost;
}a[1005];
int cmp(cc a,cc b)
{
return a.x<b.x;
}
int dp[1005];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
a[i].x=x,a[i].y=y,a[i].cost=z;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
dp[i]=a[i].cost;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<i;j++)
{
if(a[i].x>=a[j].y)
{
dp[i]=max(dp[i],dp[j]+a[i].cost);
}
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
ans=max(ans,dp[i]);
}
printf("%d",ans);
return 0;
}
题目描述 Description
在一个数轴上有n条线段,现要选取其中k条线段使得这k条线段两两没有重合部分(端点可以重合),问最大的k为多少。
输入描述 Input Description
输入格式
输入文件的第1行为一个正整数n,下面n行每行2个数字ai,bi,描述每条线段。
输出描述 Output Description
输出格式
输出文件仅包括1个整数,为k的最大值
样例输入 Sample Input
3
0 2
2 4
1 3
样例输出 Sample Output
2
数据范围及提示 Data Size & Hint
数据范围
对于20%的数据,n≤10;
对于50%的数据,n≤1000;
对于70%的数据,n≤100000;
对于100%的数据,n≤1000000,0≤ai<bi≤1000000。
思路:除了数据范围之外,和线段覆盖1一模一样。
题解:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct cc{
int x,y;
}a[1000005];
int cmp(cc a,cc b)
{
if(a.y==b.y)
{
return a.x>b.x;
}
return a.y<b.y;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>a[i].x>>a[i].y;
if(a[i].x>a[i].y)
{
swap(a[i].x,a[i].y);
}
}
sort(a+1,a+n+1,cmp);
int last=-21478364;
int ans=0;
for(int i=1;i<=n;i++)
{
if(a[i].x>=last)
{
ans++;
last=a[i].y;
}
}
printf("%d",ans);
return 0;
}
题目描述 Description
数轴上有n条线段,线段的两端都是整数坐标,坐标范围在0~1000000,每条线段有一个价值,请从n条线段中挑出若干条线段,使得这些线段两两不覆盖(端点可以重合)且线段价值之和最大。
输入描述 Input Description
第一行一个整数n,表示有多少条线段。
接下来n行每行三个整数, ai bi ci,分别代表第i条线段的左端点ai,右端点bi(保证左端点<右端点)和价值ci。
输出描述 Output Description
输出能够获得的最大价值
样例输入 Sample Input
3
1 2 1
2 3 2
1 3 4
样例输出 Sample Output
4
数据范围及提示 Data Size & Hint
n <= 1000000
0<=ai,bi<=1000000
0<=ci<=1000000
数据输出建议使用long long类型(Pascal为int64或者qword类型)
思路:二分+动态规划
题解:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct cc{
long long x,y,cost;
}a[1000000+10];
long long n;
long long dp[1000000+10];
long long cmp(cc a,cc b)
{
return a.y<b.y;
}
long long find(long long now)
{
long long l=1,r=n;
while(l<=r)
{
long long mid=(l+r)/2;
if(a[mid].y<now) l=mid+1;
else r=mid-1;
}
if(a[l].y<=now)
{
return l;
}
else
{
return l-1;
}
}
int main()
{
scanf("%lld",&n);
long long m=0,ans=0;
for(long long i=1;i<=n;i++)
{
scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].cost);
m=max(m,a[i].y);
}
sort(a+1,a+n+1,cmp);
for(long long i=1;i<=m;i++)
{
long long now=find(i);
if(now>=1&&now<=n)
{
for(int j=a[now].y;j<=i;j++)
{
dp[i]=max(dp[a[j].x]+a[j].cost,max(ans,dp[i]));
}
}
ans=max(dp[i],ans);
}
printf("%lld",ans);
return 0;
}