做题感悟:这是接触的单调队列的第一题,终于把它弄懂了,结合白书以及网上的各种资料。
解题思路: 单调队列DP
这题的重点就在变换动态转移方程上,首先设 dp[ i ] 为处理到第 i 个垃圾所用的最小距离,那么很容易想到动态转移方程:dp[ i ] = min { dp[ j ] + d( j + 1 ) + d( j + 1 , i ) + d( i ) } 且 w( j + 1 , i ) <= W , 解释一下:d( i ) 为 i 点到原点的距离(指哈密顿距离),d( j + 1 ,i) 代表 从j + 1 到 i 的距离和。w(j + 1 , i ) 为从 j
+ 1 到 i 的重量和。W 为最大重量。
好了,接下来就是怎样去转化动态方程了:我们用前缀和的思想分别记录前缀距离和前缀重量,分别用数组 sumd[ i ] ,sumw[ i ] ,d[ i ] 为点i 到原点的距离,这样方程就可以变为:
dp[ i ] = min { dp[ j ] + d[ j +1 ] + sumd[ i ] - sumd[ j + 1] + d[ i ] } 且 sumw[ i ] - sum[ j ] <= W ;
进一步转变 ===>
dp[ i ] = min{dp[ j ] + d[ j + 1 ] - sumd[ j + 1 ] } + sumd[ i ] + d[ i ] ; 变成这样后你会发现前面的各个数只与本身相关,可以把他们放入一个队列中,只要维护队列的最小值(在重量满足的前提下),那么计算dp[ i ]的时间就变成O( 1 ) 的了。
具体见代码:
#include<iostream> #include<sstream> #include<map> #include<cmath> #include<fstream> #include<queue> #include<vector> #include<sstream> #include<cstring> #include<cstdio> #include<stack> #include<bitset> #include<ctime> #include<string> #include<cctype> #include<iomanip> #include<algorithm> using namespace std ; #define INT long long int #define L(x) (x * 2) #define R(x) (x * 2 + 1) const int INF = 0x3f3f3f3f ; const double esp = 0.0000000001 ; const double PI = acos(-1.0) ; const int mod = 1000000007 ; const int MY = (1<<5) + 5 ; const int MX = 100010 + 5 ; int n ,W ; int sumw[MX] ,d[MX] ,dp[MX] ,deq[MX] ,sumd[MX] ; int Cavalue(int j) { return dp[j] + d[j+1] - sumd[j+1] ; } void input() { int x ,y ,w ; scanf("%d%d" ,&W ,&n) ; sumw[0] = sumd[0] = d[0] = 0 ; int x1 = 0 ,y1 = 0 ; for(int i = 1 ;i <= n ; ++i) { scanf("%d%d%d" ,&x ,&y ,&w) ; sumw[i] = sumw[i-1] + w ; // 重量的前缀和 d[i] = abs(x) + abs(y) ; // 到原点的距离 sumd[i] = sumd[i-1] + abs(x-x1) + abs(y-y1) ; // 距离前缀和 x1 = x ; y1 = y ; } } void DP() { memset(deq ,0 ,sizeof(deq)) ; int front = 0 ,end = 0 ; // deq 双端队列的头和尾 for(int i = 1 ;i <= n ; ++i) { while(front < end && Cavalue(deq[end-1]) >= Cavalue(i-1)) end-- ; deq[end++] = i-1 ; while(front < end && sumw[i] - sumw[deq[front]] > W) front++ ; dp[i] = Cavalue(deq[front]) + d[i] + sumd[i] ; } } int main() { int Tx ; scanf("%d" ,&Tx) ; while(Tx--) { input() ; DP() ; cout<<dp[n]<<endl ; if(Tx) cout<<endl ; } return 0 ; }
时间: 2024-11-05 04:51:44