zoukankan      html  css  js  c++  java
  • 蛋糕(区间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;
    }
    
  • 相关阅读:
    VS2010 自动跳过代码现象
    Reverse Linked List II 【纠结逆序!!!】
    Intersection of Two Linked Lists
    Linked List Cycle II
    Remove Nth Node From End of List 【另一个技巧,指针的指针】
    Swap Nodes in Pairs
    Merge Two Sorted Lists
    Remove Duplicates from Sorted List
    Linked List Cycle
    Dungeon Game
  • 原文地址:https://www.cnblogs.com/rui-4825/p/14055386.html
Copyright © 2011-2022 走看看