烽火传递(dp+单调队列)
烽火台又称烽燧,是重要的军事防御设施,一般建在险要或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息;夜晚燃烧干柴,以火光传递军情,在某两座城市之间有 n 个烽火台,每个烽火台发出信号都有一定代价。为了使情报准确地传递,在连续 m 个烽火台中至少要有一个发出信号。请计算总共最少花费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确传递。
Input
第一行:两个整数 N,M。其中N表示烽火台的个数, M 表示在连续 m 个烽火台中至少要有一个发出信号。接下来 N 行,每行一个数 Wi,表示第i个烽火台发出信号所需代价。
Output
一行,表示答案。
Sample Input
5 3
1
2
5
6
2
Sample Output
4
Data Constraint
对于50%的数据,M≤N≤1,000 。 对于100%的数据,M≤N≤100,000,Wi≤100。
分析:
定义f[i]为点燃第i个烽火时前i个烽火满足条件的最小值。则状态转移方程为:
f[i]=min(f[j])+a[i]. 其中 i-m<=j<=i-1;
由此可以得出一般的解法:
#include <iostream>//烽火传递问题。 using namespace std; const int inf=1e6+7; int a[inf]; int f[inf]; /*状态转移方程 : 定义f[i]: 点燃第i个烽火,并且前i个满足条件。 则:f[i]=(min)f[j]+a[i] i-m<=j<=i-1; 状态转移方程。 */ int main() {int n,m;scanf("%d %d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",&a[i]);f[0]=0;for(int i=1;i<=m;i++)f[i]=a[i];for(int i=m+1;i<=n;i++){long long themax= ~(1<<31);for(int j=i-m;j<=i-1;j++){if(f[j]<themax)themax=f[j]; }f[i]=themax+a[i];}long long tmax=1<<30;for(int i=n;i>n-m;i--){if(f[i]<tmax)tmax=f[i];} cout<<tmax<<endl;return 0; }但是从以上程序中也可以看出复杂度为O(n的平方),对应题目而言显然是不行的,并且注意到是线性结构,求其最小值,所以可以使用单调队列进行优化。单调队列我认为和单调函数差不多,不是单调递增就是单调递减,只要在入队的时候保持队列的单调性就行了,并且弹出比入队元素大的元素就可以了。
代码:
总结
以上是生活随笔为你收集整理的烽火传递(dp+单调队列)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 线性筛素数欧拉函数
- 下一篇: 算个欧拉函数给大家助助兴(米勒拉宾(判断