• 蛋糕(区间DP)+东方记者(普通DP)


    最近考试总是DP签到题,本身就是个弱项, 写个小结

    蛋糕

    大意

    Solution

    为了简化问题(名称)
    先声明“我”是第一个拿蛋糕的那个人
    “我”想要得到最大值
    定义(dp[i][j])表示取完区间(i,j)我能得到的最大值并且最后一次是我取走的
    考虑如何转移
    对答案有贡献的区间长度为奇数
    因为根据定义要保证最后一次是我取的

    • 最后一次我取走了(a[i])
      那么(dp[i][j])将从状态(dp[i+1][j])转移得到
      又因为区间长度为奇数,这一次转移的最后一次是另一个人取的
      考虑再往前一步的操作
      就是另一个人取走了(a[i+1])或者(a[j])

      • 假设另一人取走了(a[i+1])
        那么上一步的状态变为(dp[i+2][j])
        因为在这一步当中状态方程表示的是(dp[i+2][j])证明整段区间已经被选完了
        所以另一个人是在(a[i+1])(a[j+1])中选择了(a[i+1])
        当且仅当在(a[i+1]>a[j+1])时成立
      • 假设另一人取走了(a[j])
        同理推断另一人是在(a[j])(a[i])当中选择了前者
        上一步状态变为(dp[i+1][j-1])
        当且仅当在(a[j] > a[i])时成立
    • 最后一次我取走了(a[j])
      状态将从(dp[i][j - 1])转移得到
      另一个人取走了(a[i])(a[j-1])

      • 假设另一人取走了(a[i])
        区间(i+1, j)已经被选完了
        状态变为(dp[i+1][j-1])
        (a[i]>a[j])时成立
      • 假设另一人取走了(a[j-1])
        区间(i, j-2)已经被选完了
        状态变为(dp[i][j-2])
        (a[j-1]>a[i-1])时成立

    判断边界可以出代码了

    Code

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #define int long long
    #define max(a, b) ({register int AA = a, BB = b; AA > BB ? AA : BB;})
    using namespace std;
    
    inline int read(){
    	int x = 0, w = 1;
    	char ch = getchar();
    	for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
    	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
    	return x * w;
    }
    
    const int ss = 4004;
    
    int dp[ss][ss], a[ss];
    
    signed main(){
    	register int ans = 0;
    	register int n = read();
    	for(register int i = 1; i <= n; i++)
    		a[n + i] = a[i] = read();
    	for(register int i = 1; i <= n + n; i++)
    		dp[i][i] = a[i];
    	for(register int len = 3; len <= n; len += 2){
    		for(register int i = 1; i + len - 1 <= n + n; i++){
    			register int j = i + len - 1;
    			if(a[i + 1] > a[j + 1] && j + 1 <= n + n && i + 1 <= n + n) dp[i][j] = max(dp[i][j], dp[i + 2][j] + a[i]);
    			if(a[i] < a[j]) dp[i][j] = max(dp[i][j], dp[i + 1][j - 1] + a[i]);
    			if(a[i] > a[j]) dp[i][j] = max(dp[i][j], dp[i + 1][j - 1] + a[j]);
    			if(a[i - 1] < a[j - 1] && i - 1 >= 1 && j - 1 >= 1) dp[i][j] = max(dp[i][j], dp[i][j - 2] + a[j]);
    			ans = max(ans, dp[i][j]);
    		}
    	}
    	cout << ans << endl;
    	return 0;
    }
    

    东方记者

    大意

    在坐标系中给出n个点(信息),以及移动距离的限制
    距离表示为曼哈顿距离
    问在移动限制内最多能走到多少点(采集多少信息)

    Solution

    定义(dp[i][j])表示走到第(i)个点收集(j)个信息的最小的代价
    考虑转移
    (dp[j][k])(dp[i][k+1])证明从(j)走到了(i),收集到了第(k+1)个信息
    代价为从(j)(i)的曼哈顿距离
    统计答案
    枚举对于每个点能收集(j)个信息
    如果走到当前点收集(j)个信息的代价比限制要少
    (j)更新答案即可

    Code

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #define max(a, b) ({register long long AA = a, BB = b; AA > BB ? AA : BB;})
    #define min(a, b) ({register long long AA = a, BB = b; AA < BB ? AA : BB;})
    #define getdis(i, j) (abs(x[i] - x[j]) + abs(y[i] - y[j]))
    using namespace std;
    
    inline long long read(){
    	register long long x = 0, w = 1;
    	char ch = getchar();
    	for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
    	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
    	return x * w;
    }
    
    const int ss = 105;
    
    long long dp[105][105];
    long long x[ss], y[ss];
    
    signed main(){
    	register int n = read();
    	memset(dp, 0x7f, sizeof dp);
    	for(register int i = 1; i <= n; i++){
    		x[i] = read(), y[i] = read();
    		dp[i][1] = abs(x[i]) + abs(y[i]);
    	}
    	register long long d = read();
    	for(register int i = 2; i <= n; i++)
    		for(register int j = 1; j <= i - 1; j++)
    			for(register int k = 1; k <= j; k++)
    				dp[i][k + 1] = min(dp[i][k + 1], dp[j][k] + getdis(i, j));
    	register long long ans = 0;
    	for(register int i = 1; i <= n; i++)
    		for(register int j = 1; j <= i; j++){
    			if(abs(x[i]) + abs(y[i]) + dp[i][j] <= d)//在j处收集的代价足够,收集j
    				ans = max(ans, j);
    		}
    	printf("%lld
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    MySQL数据库高可用集群搭建-PXC集群部署
    高性能高并发网站架构,教你搭建Redis5缓存集群
    redis连接错误3种解决方案System Error MISCONF Redis is configured to save RDB snapshots
    进程异常行为-反弹Shell攻击,KILL多个进程
    Laravel中我们登录服务器通过 Tinker 手动创建后台管理用户
    Laravel5.x的php artisan migrate数据库迁移创建操作报错SQLSTATE[42000]解决
    Laravel:php artisan key:generate三种报错解决方案,修改默认PHP版本(宝塔面板)
    大型网站如何防止崩溃,解决高并发带来的问题
    PHP微信公众平台OAuth2.0网页授权,获取用户信息代码类封装demo(二)
    iOS开发 ReactiveCocoa入门教程 第二部分
  • 原文地址:https://www.cnblogs.com/rui-4825/p/14055386.html
Copyright © 2020-2023  润新知