烽火传递(dp+单调队列)
烽火臺又稱烽燧,是重要的軍事防御設施,一般建在險要或交通要道上。一旦有敵情發(fā)生,白天燃燒柴草,通過濃煙表達信息;夜晚燃燒干柴,以火光傳遞軍情,在某兩座城市之間有 n 個烽火臺,每個烽火臺發(fā)出信號都有一定代價。為了使情報準確地傳遞,在連續(xù) m 個烽火臺中至少要有一個發(fā)出信號。請計算總共最少花費多少代價,才能使敵軍來襲之時,情報能在這兩座城市之間準確傳遞。?
?
Input
第一行:兩個整數(shù) N,M。其中N表示烽火臺的個數(shù), M 表示在連續(xù) m 個烽火臺中至少要有一個發(fā)出信號。接下來 N 行,每行一個數(shù) Wi,表示第i個烽火臺發(fā)出信號所需代價。
Output
一行,表示答案。
Sample Input
5 3 ?
1 ?
2 ?
5 ?
6 ?
2
Sample Output
4
Data Constraint
對于50%的數(shù)據(jù),M≤N≤1,000 。 對于100%的數(shù)據(jù),M≤N≤100,000,Wi≤100。
?
分析:
定義f[i]為點燃第i個烽火時前i個烽火滿足條件的最小值。則狀態(tà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]; /*狀態(tài)轉移方程 : 定義f[i]: 點燃第i個烽火,并且前i個滿足條件。 則:f[i]=(min)f[j]+a[i] i-m<=j<=i-1; 狀態(tài)轉移方程。 */ 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的平方),對應題目而言顯然是不行的,并且注意到是線性結構,求其最小值,所以可以使用單調(diào)隊列進行優(yōu)化。單調(diào)隊列我認為和單調(diào)函數(shù)差不多,不是單調(diào)遞增就是單調(diào)遞減,只要在入隊的時候保持隊列的單調(diào)性就行了,并且彈出比入隊元素大的元素就可以了。
代碼:
?
?
?
?
?
總結
以上是生活随笔為你收集整理的烽火传递(dp+单调队列)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 线性筛素数欧拉函数
- 下一篇: 算个欧拉函数给大家助助兴(米勒拉宾(判断