• [Noip 2009 普及组 T4] [Luogu P1070] 道路游戏


    一道很迷的(dp)

    感谢大爱无疆的sy

    开始的时候采用的二维状态但是并不对)

    然后把状态改成一维(AC)

    (Solution)

    状态:开始想的是(f[i][j]),表示到达(i)时间时在(j)点处的最多金币数。

    转移方程设置为:(f[i][j]=max{f[i-1][j-k]+sum-val[j-k]})其中(sum)表示从(j-k)走到(j)所赚的金币数

    但这样是不对的,因为题目中:

    也就是上一个机器人消失的地方并不一定要买下一个机器人,而是可以换另一个地方买。

    如果硬要设计地点的话,应该将(f[i-1][j-k])变为(max{f[i-1][1,2,……n]})

    这样时间复杂度是(O(n^4))的,想过题可能在想(peach)

    经过思考,我们发现地点是没什么用的,所以将第二维去掉,(f[i])表示时间为(i)时能获得的最大金币数;

    转移方程:(f[i]=max{f[i-k]+sum-val[d],d=(j-k)\%n+n})

    表示在(d)点购买的机器人从(d)点走到(j)点赚取的金币数,枚举(j、d),取得(f[i])时的最大值

    (sum)表示从(d)走到(j)获得的金币数,最简单的方法,暴力求解:

    int pay(int a,int b,int x,int y) {
    	int rtn=0,j=a;
    	for(int i=x+1;i<=y;i++) {
    		rtn+=cost[j][i];
    		j++;
    		if(j>n) j=1;
    	}
    	return rtn;
    }
    //表示从a走到b,时间从x变成y所获得的金币数
    
    

    (Code):

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read() {
    	int ans=0;
    	char last=' ',ch=getchar();
    	while(ch>'9'||ch<'0') last=ch,ch=getchar();
    	while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
    	if(last=='-') ans=-ans;
    	return ans;
    }
    
    int n,m,p; 
    int cost[1010][1010];
    int val[1010];
    int f[1010];
    
    int pay(int a,int b,int x,int y) {
    	int rtn=0,j=a;
    	for(int i=x+1;i<=y;i++) {
    		rtn+=cost[j][i];
    		j++;
    		if(j>n) j=1;
    	}
    	return rtn;
    }
    
    int main() {
    	n=read();
    	m=read();
    	p=read();
    	for(int i=1;i<=n;++i) 
    		for(int j=1;j<=m;++j) 
    			cost[i][j]=read(); 
    	for(int i=1;i<=n;++i) 
    		val[i]=read();
    	memset(f,0x9f,sizeof(f));
    	f[0]=0;
    	for(int i=1;i<=m;++i) { // time i
    		for(int j=1;j<=n;++j) { // node j
    			for(int k=1;k<=p&&k<=i;++k) { // k
    				int d=j-k; 
    				if(d<=0) 
    					d=d%n+n;
    				int sum=pay(d,j,i-k,i);
    				f[i]=max(f[i],f[i-k]+sum-val[d]);
    			}
    		}
    	}
    	printf("%d",f[m]);
    	return 0;
    }
    

    这样会(TLE),求(pay)实在是太慢了。

    因为(k)是从小到大枚举的,也就是从只从(j)往后退一步,到往后退(p)步,赚取的金币数刚好是可以累加的。

    所以定义一个(sum=0)每次枚举(k)时,(sum+=cost[j-k][i-k+1])

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read() {
    	int ans=0;
    	char last=' ',ch=getchar();
    	while(ch>'9'||ch<'0') last=ch,ch=getchar();
    	while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
    	if(last=='-') ans=-ans;
    	return ans;
    }
    
    int n,m,p; 
    int cost[1010][1010];
    int val[1010];
    int f[1010];
    
    int main() {
    	n=read();
    	m=read();
    	p=read();
    	for(int i=1;i<=n;i++) 
    		for(int j=1;j<=m;j++) 
    			cost[i][j]=read();
    	for(int i=1;i<=n;i++) 
    		val[i]=read();
    	memset(f,0x9f,sizeof(f));
    	f[0]=0;
    	for(int i=1;i<=m;i++) { // time i
    		for(int j=1;j<=n;j++) { // node j
    			int sum=0;
    			for(int k=1;k<=p&&k<=i;k++) { // zoule k
    				int d=j-k; 
    				if(d<=0) 
    					d=d%n+n;
    				sum+=cost[d][i-k+1];
    				f[i]=max(f[i],f[i-k]+sum-val[d]);
    			}
    		}
    	}
    	printf("%d",f[m]);
    	return 0;
    }
    
  • 相关阅读:
    微信小程序入门
    webpack
    模块化开发(1)
    HTML5表单
    移动端入门
    MySQL
    js面向对象与PHP面向对象总结
    PHP
    Git指令
    Redux
  • 原文地址:https://www.cnblogs.com/zhuier-xquan/p/12114538.html
Copyright © 2020-2023  润新知