版权声明:转载无所谓的。。。 https://blog.csdn.net/xuxiayang/article/details/82953137
大意
给定 头牛所在的一些位置,现在要用不大于 块连续的木板把每头牛拦住,问最少需要的木板总长度
思路
动态规划
设
表示前
个牛,用了
个木板的最小木板总长度。
分两种情况
- 我木板够,则
- 我木板不够,则
因为我们要使总长度尽量短,所以 也要尽量小,那么我们就可以排序后处理即可
时间复杂度为:
空间复杂度为:
然后我们发现, 只跟 有关,所以我们可以用滚动数组优化,空间复杂度降低到了:
其实还有一种优化,就是如果我们把 倒过来循环的话,那么 就必然是上一次的,这样空间复杂度就进一步降低到了:
代码
/*
ID:hzbismy1
LANG:C++
TASK:barn1
*/
#include<cstdio>
#include<algorithm>
using namespace std;int f[51],n,m,s,a[201];
signed main()
{
freopen("barn1.in","r",stdin);
freopen("barn1.out","w",stdout);
scanf("%d%d%d",&m,&s,&n);
if(m>=n)return printf("%d",n)&0;//特判
for(register int i=1;i<=n;i++) scanf("%d",a+i);
sort(a+1,a+1+n);//排序减小差值
for(register int i=1;i<=n;f[0]=502345678,i++)//记得把f[0]赋值为无穷大
for(register int j=m;j>0;j--) f[j]=min(f[j-1]+1,f[j]+a[i]-a[i-1]);//动态转移
printf("%d",f[m]);//输出
}
贪心思路
首先我们假设一开始有一块长度为 的木板拦住了所有的牛,然后断开 处,既然要使木板的总长度尽量小,那我们断开的木板的长度一定要尽量长,我们先算出每头牛它左边(或右边)与它最近的牛的长度,然后排序,依次减去长度更长的,就一定满足是最优的(因为只会断开那些无用的地方,所以答案是可行的)
代码
#include<cstdio>
#include<algorithm>
using namespace std;int n,m,s,a[201],cz[201],ans;
signed main()
{
scanf("%d%d%d",&m,&s,&n);
if(m>=n)return printf("%d",n)&0;
for(register int i=1;i<=n;i++) scanf("%d",a+i);
sort(a+1,a+1+n);
ans=a[n]-a[1]+1;//一开始一个木板拦住了所有的牛
for(register int i=2;i<=n;i++) cz[i-1]=a[i]-a[i-1];//计算差值
sort(cz+1,cz+n);//排序
for(register int i=n-1,j=1;j<m;j++,i--) ans=ans-cz[i]+1;//减去差值最大的那几个段
printf("%d",ans);//输出
}