标签:
第一部分:题目
给定x轴上的N(0<N<100)条线段,每个线段由它的二个端点a_I和b_I确定,I=1,2,……N.这些坐标都是区间(-999,999)的整数。有些线段之间会相互交叠或覆盖。请你编写一个程序,从给出的线段中去掉尽量少的线段,使得剩下的线段两两之间没有内部公共点。所谓的内部公共点是指一个点同时属于两条线段且至少在其中一条线段的内部(即除去端点的部分)。
输入第一行是一个整数N。接下来有N行,每行有二个空格隔开的整数,表示一条线段的二个端点的坐标。
输出第一行是一个整数表示最多剩下的线段数。
3
6 3
1 3
2 5
2
0<N<100
第二部分:思路
这题所谓的贪心就是指怎么去掉一段线段使得总的有内部公共点的线段最少,为了描述方便就称与某一线段有内部公共点的线段数为“邻居数”。那么就需要去除当前与其他线段内部公共点最多的线段。在删除该线段时,与它有内部公共点的线段的邻居数减一。那么就需要获取每条线段的邻居数,在每次输入新线段时进行比较,计算出当前每条线段的邻居数。然后就根据这原理去除线段,在剩下的所有线段的邻居数都为0时就可以了。
第三部分:代码
#include<stdio.h> #include<string.h> int sum(int s[100][3],int len)//判断线段是否有内部公共点 { int i; for(i=1;i<=len;i++) { if(s[i][2]>0) { return 1; } } return 0; } int main() { int n,s[100][3]={0},i,j,a,b; scanf("%d",&n); for(i=1;i<=n;i++)//把线段默认编号为1~n { scanf("%d%d",&a,&b);//输入线段的两个端点 int t; if(a>b)//因为从题目看出,两个端点并非a<b,调整为a<b方便后面判断 { t=a; a=b; b=t; } s[i][0]=a; s[i][1]=b; for(j=1;j<i;j++) { //a>s[j][0]&&a<s[j][1]||b>s[j][0]&&b<s[j][1]:两个线段之间是交叉关系或者 //<a,b>包含于其他线段 //a<=s[j][0]&&b>=s[j][1]:<a,b> 包含其他线段 if(a>s[j][0]&&a<s[j][1]||b>s[j][0]&&b<s[j][1]||a<=s[j][0]&&b>=s[j][1]) { s[j][2]++;//与该线段用公共点的线段个数 s[i][2]++; } } } int count=0;//记录去除的线段数 while(sum(s,n)) { count++; int max=0,i,index; for(i=1;i<=n;i++)//找出当前所剩线段的邻居数最大的线段 { if(s[i][2]>max) { max=s[i][2]; index=i; } } int a,b; a=s[index][0]; b=s[index][1]; for(i=1;i<=n;i++) { //当去除某条线段时,与之有内部公共点的线段的邻居数减一 //注意s[i][2]>0,已经去除的线段不再考虑 if(s[i][2]>0&&(a>s[i][0]&&a<s[i][1]||b>s[i][0]&&b<s[i][1] ||a<=s[i][0]&&b>=s[i][1])) { s[i][2]--; } } s[index][2]=0;//去除后的线段的邻居数置为0 max=0; } printf("%d\n",n-count); return 0; }
1214 线段覆盖——http://codevs.cn/problem/1214/
标签:
原文地址:http://www.cnblogs.com/xiangguoguo/p/5384512.html