#P1746. 第1题-小红的彩灯节
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 212
            Accepted: 57
            Difficulty: 4
            
          
          
          
                       所属公司 : 
                              阿里
                                
            
                        
              时间 :2024年3月24日-阿里云
                              
                      
          
 
- 
                        算法标签>动态规划          
 
第1题-小红的彩灯节
题解
简述一下题意,有 n 盏灯,每个灯有两种颜色,每种颜色对应一个权值,可以选择一种颜色点亮,或者不点点,不能有两盏连续的灯颜色相同。
这题是 Leetcode上的 打家劫舍 变形题,是一类动态规划的问题。
定义 f[i][j] 为,考虑前 i 盏灯,且最后一盏灯的状态为 jj∈[0,1,2] 的最大权值。
状态转移为:
for(int t = 0; t < 3; t ++)
		for(int k = 0; k < 3; k ++)
			if(k != t)
				f[i][t] = max(f[i][t], f[i - 1][k]) + (对应的权值) // 只要上盏灯不和这盏灯状态相同即可转移
时间复杂度为 : O(n)
AC代码
- Cpp
 
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main (){
    ios::sync_with_stdio(false);
    std::cin.tie(0);
    int n; cin >> n;
    vector<vector<int>> a(n, vector<int>(2));
    for(int i = 0; i < n; i ++)
        cin >> a[i][0] >> a[i][1];
    vector<vector<int>> dp(n, vector<int>(3, -1));
    auto dfs = [&](auto dfs, int u, int c) -> int{
        if(u == n)
            return 0;
        if(dp[u][c] != -1)
            return dp[u][c];
        
        int res = dfs(dfs, u + 1, 0);
        if(c)
        {
            int r = 3 - c;
            res = max(dfs(dfs, u + 1, r) + a[u][r - 1], res);
        }
        else
        {
            res = max(res, dfs(dfs, u + 1, 1) + a[u][0]);
            res = max(res, dfs(dfs, u + 1, 2) + a[u][1]); 
        }
        dp[u][c] = res;
        return res; 
    };
    int res = dfs(dfs, 0, 0);
    cout << res << "\n";
    return 0;
}
- python
 
import sys
sys.setrecursionlimit(2000000)
def dfs(u, c):
    if u == n:
        return 0
    if dp[u][c] != -1:
        return dp[u][c]
    
    res = dfs(u + 1, 0)
    if c:
        r = 3 - c
        res = max(dfs(u + 1, r) + a[u][r - 1], res)
    else:
        res = max(res, dfs(u + 1, 1) + a[u][0])
        res = max(res, dfs(u + 1, 2) + a[u][1])
    
    dp[u][c] = res
    return res
n = int(input())
a = [list(map(int, input().split())) for _ in range(n)]
dp = [[-1] * 3 for _ in range(n)]
res = dfs(0, 0)
print(res)
- Java
 
import java.util.Scanner;
public class Main {
    static int n;
    static long[][] a;
    static long[][] dp;
    static long dfs(int u, int c) {
        if (u == n) return 0;
        if (dp[u][c] != -1) return dp[u][c];
        long res = dfs(u + 1, 0);
        if (c != 0) {
            int r = 3 - c;
            res = Math.max(dfs(u + 1, r) + a[u][r - 1], res);
        } else {
            res = Math.max(res, dfs(u + 1, 1) + a[u][0]);
            res = Math.max(res, dfs(u + 1, 2) + a[u][1]);
        }
        dp[u][c] = res;
        return res;
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        a = new long[n][2];
        dp = new long[n][3];
        for (int i = 0; i < n; i++) {
            a[i][0] = scanner.nextLong();
            a[i][1] = scanner.nextLong();
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < 3; j++) {
                dp[i][j] = -1;
            }
        }
        long res = dfs(0, 0);
        System.out.println(res);
    }
}
        问题描述
小红的家乡即将举行一年一度的彩灯节。节日中,小红负责布置一排彩灯,每个彩灯可以选择亮起“红”或“绿”两种颜色,用红色代表喜庆,会增加喜气值;用绿色代表和谐,会增加安宁值。但是为了避免颜色单调,相邻的灯不能亮起相同的颜色。在确保相邻彩灯颜色不同的前提下,小红想知道如何点亮这些彩灯才能使得喜气值和安宁值的总和最大。
输入格式
第一行包含一个正整数 n,表示彩灯的总数。
接下来 n 行,每行两个正整数 ri 和 gi,分别表示第 i 个彩灯亮起红色和绿色时所增加的喜气值和安宁值。
输出格式
输出一行一个整数,表示小红点亮彩灯后能获得的最大总和值。
样例输入
4
1 3
4 3
5 6
2 3
样例输出
15
评测数据与规模
- 1≤n≤105,1≤ri,gi≤109。