P1070 [NOIP2009 普及组] 道路游戏

算法要素:暴力dp+超长题面的阅读理解
思路分析:

先找出几个细节:
(1)每一个时刻都必须有机器人位于环上。
(2)对于每个时刻 i i i,在 i i i制造的机器人一定会花 1 1 1的单位时间收集位于第 i i i条边上的金币。
(3)每次可以从任意位置开始重新选择机器人。

然后可以选择 d p [ i ] dp[i] dp[i]表示时刻 i i i的最大收益

经验总结:

(1)最开始发现这道题有环,习惯性地想到破环成链,然后可以发现破环成链的条件:
环只有一层,且环是静态的。
(2)dp有时需要尽量考虑 d p [ i ] dp[i] dp[i] d p [ i − 1 ] dp[i-1] dp[i1]转移的方法,因为这样可以通过
用前面处理完的情况覆盖后面的情况以减少决策点。(虽然这道题跟这个好像没什么关系)
(3)dp不一定是从 d p [ i − k ] dp[i-k] dp[ik] d p [ i ] dp[i] dp[i]转移,可以考虑 d p [ i ] dp[i] dp[i] d p [ i + k ] dp[i+k] dp[i+k]转移

ps:这个做法是跑不满的 O ( n 3 ) O(n^3) O(n3)暴力,正解有单调队列优化,以后会考虑写一下。

Code

#include
using namespace std;
const int maxn=1e3+30;
int dp[maxn],w[maxn];
int n,m,p;
int val[maxn][maxn];
int main()
{
	scanf("%d%d%d",&n,&m,&p);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)	
			scanf("%d",&val[i][j]);
	for(int i=1;i<=n;++i) scanf("%d",&w[i]);
	for(int i=1;i<=m;++i) dp[i]=-1e9;
	for(int i=1;i<=m;++i)
	{
		for(int j=1;j<=n;++j)
		{
			int ans=-w[j]+dp[i-1];
			for(int k=0;k<p && i+k<=m;++k)
			{
				int t=j+k;
				if(t>n) t=t%n;
				ans+=val[t][i+k];
				dp[i+k]=max(dp[i+k],ans);
			}
		}
	}
	printf("%d",dp[m]);
	return 0;
}

你可能感兴趣的:(动态规划,算法)