Problem Description
用i来表示x坐标轴上坐标为[i-1,i]的长度为1的区间,并给出n(1≤n≤200)个不同的整数,表示n个这样的区间。
现在要求画m条线段覆盖住所有的区间,
条件是:每条线段可以任意长,但是要求所画线段的长度之和最小,
并且线段的数目不超过m(1≤m≤50)。
Input
输入包括多组数据,每组数据的第一行表示区间个数n和所需线段数m,第二行表示n个点的坐标。
Output
每组输出占一行,输出m条线段的最小长度和。
Example Input
5 3 1 3 8 5 11
Example Output
7
问题大概意思就是给你n个区间,要用m条线段覆盖它, 求最短的m条线段之和。
大概思路呢,首先画一条线段刚好覆盖所有的区间,然后呢再找出各个区间的间隔大小,从大倒小排序,依次把间隔从线段上划掉,直到线段变成m条为止,剩下的就是最短线段之和了
代码如下:
#include <stdio.h>
//排序函数(从大到小)
void f(int a[], int l, int r)
{
int i = l, j = r;
int key = a[l];
if(l > r)
return ;
while(i < j)
{
while(i < j && a[j] <= key)
j--;
a[i] = a[j];
while(i < j && a[i] >= key)
i++;
a[j] = a[i];
a[i] = key;
}
f(a,l,i-1);
f(a,i+1,r);
}
int main()
{
int i, n, m;
int a[205], d[205];
while(~scanf("%d %d", &n, &m))
{
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
f(a,0,n-1);
for(i = 0; i < n-1; i++) //求出各个间隔
d[i] = a[i] - a[i+1] - 1;
f(d,0,n-2); //从大到小排序间隔
if(m > n) //如果m>n,直接输出n
printf("%d\n", n);
else
{
int nline = 1; //初始线段数
int tl = a[0] - a[n-1] + 1; //初始线段总长
int devide = 0;
while(nline < m && d[devide] > 0)
{
nline++;
tl = tl - d[devide]; //减去间隔
devide++;
}
printf("%d\n", tl);
}
}
return 0;
}
//排序函数(从大到小)
void f(int a[], int l, int r)
{
int i = l, j = r;
int key = a[l];
if(l > r)
return ;
while(i < j)
{
while(i < j && a[j] <= key)
j--;
a[i] = a[j];
while(i < j && a[i] >= key)
i++;
a[j] = a[i];
a[i] = key;
}
f(a,l,i-1);
f(a,i+1,r);
}
int main()
{
int i, n, m;
int a[205], d[205];
while(~scanf("%d %d", &n, &m))
{
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
f(a,0,n-1);
for(i = 0; i < n-1; i++) //求出各个间隔
d[i] = a[i] - a[i+1] - 1;
f(d,0,n-2); //从大到小排序间隔
if(m > n) //如果m>n,直接输出n
printf("%d\n", n);
else
{
int nline = 1; //初始线段数
int tl = a[0] - a[n-1] + 1; //初始线段总长
int devide = 0;
while(nline < m && d[devide] > 0)
{
nline++;
tl = tl - d[devide]; //减去间隔
devide++;
}
printf("%d\n", tl);
}
}
return 0;
}