其他分享
首页 > 其他分享> > UVA1169题解

UVA1169题解

作者:互联网

题目传送门

一道很有意思的dp。

首先,这显然是一个线性 dp,状态显然是现在的垃圾编号和从哪个垃圾编号转移得到,在这里我们约定都是由。

于是我们就可以得到一个状态转移方程:

\[dp[i]=\min\limits_{1\le j \le n}\left\{dp[j]+dis(i,j)\right\},\sum^{i}_{k=j}c_k\le C \]

其中 \(dis(i,j)\) 表示从编号 \(i\) 的垃圾收集到 编号为 \(j\) 的垃圾加上从原点到两个垃圾所需的路程。

显然,转移有 \(n\) 个,而求出 \(i\) 到 \(j\) 的路径需要 \(O(n)\) 的时间,于是时间复杂度就是 \(O(n^3)\)。

显然刚才的时间复杂度过不去,而容易想到我们可以用前缀和搞一下,把复杂度变成 \(O(n^2)\)。

接着我们发现有很多状态是不合法的,因为我们需要满足 \(\sum^{i}_{k=j}c_k\le C\) 的条件。

接着我们来看看现在我们的状态转移方程:

\[dp[i]=\min\limits_{1\le j\le n}\left\{d[j]+pre[i]-pre[j+1]+x[i]+y[i]+x[j+1]+y[j+1]\right\} \]

然后我们设

\[A[i]=pre[i]+x[i]+y[i] \]

\[B[i]=d[i]-pre[i+1]+x[i+1]+y[i+1] \]

接着,我们的状态转移方程就可以写成这样

\[dp[i]=\min\limits_{1\le j\le n}\left\{A[i]+B[j]\right\} \]

还有,我们观察到 \(c_i\) 都大于 \(0\),显然 \(i-j\) 越大,\(\sum^{i}_{j=k}c_k\) 也会越大。

这时如果有一个 \(j\) 值的 \(B[j]\) 不仅小,而且离 \(i\) 远,那我们一定没有考虑这个决策的必要,这让人自然想到单调队列。

于是我们就可以优化成 \(O(n)\) 了,最后注意一下输出格式,每组数据中有空行。

Code:

#include<iostream>
using namespace std;
const int maxn=1e5+5;
inline int abs(int x) {
	return x>0?x:-x;
}
int x[maxn],y[maxn],w[maxn],d[maxn],prew[maxn],prep[maxn];
int q[maxn],l,r;
inline int f(int i){return d[i]-prep[i+1]+x[i+1]+y[i+1];}//简化B[i]
int main() {
	int t;
	cin>>t;
	while(t--) {
		int c,n;
		cin>>c>>n;
		for(int i=1; i<=n; ++i) {
			cin>>x[i]>>y[i]>>w[i];
			prep[i]=prep[i-1]+abs(x[i]-x[i-1])+abs(y[i]-y[i-1]);
			prew[i]=prew[i-1]+w[i];
		}
		l=0,r=1;
		for(int i=1; i<=n; ++i) {
			while(l<r&&prew[i]-prew[q[l]]>c)l++;
			int j=q[l];
			d[i]=d[j]+prep[i]-prep[j+1]+x[i]+y[i]+x[j+1]+y[j+1];
			while(l<r&&f(q[r-1])>=f(i))r--;
			q[r++]=i;
		}
		cout<<d[n]<<endl;
		if(t>0)cout<<endl;//注意输出格式
	}
	return 0;
}

标签:pre,le,UVA1169,题解,int,maxn,prep,dp
来源: https://www.cnblogs.com/for-hyf/p/14797592.html