首页 > 试题广场 >

小美和大富翁

[编程题]小美和大富翁
  • 热度指数:907 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\,\,\,\,\,\,\,\,\,\,小美在玩《大富翁》游戏,游戏中有 n+1 个城市排成一排,编号从 0n ,第 i 个城市上有一个数字 a_i ,表示到达第 i 个城市可以获得 a_i 枚金币。
\,\,\,\,\,\,\,\,\,\,每一轮开始时小美会获得四张卡牌,分别可以跳跃 1、2、3、4 个城市,例如小美可以从城市1跳跃 3 个城市到达城市4。当小美使用完这 4 张卡牌后,会开启新的一轮。
\,\,\,\,\,\,\,\,\,\,初始时,小美拥有 0 枚金币,在任意时刻,小美的金币数量都必须大于等于 0 ,小美想知道她从第 0 个城市出发,到达第 n 个城市最多可以获得多少枚金币。

输入描述:
\,\,\,\,\,\,\,\,\,\,第一行输入一个整数 n\ (1 \leq n \leq 10^5) 表示城市个数。
\,\,\,\,\,\,\,\,\,\,第二行输入 n 个整数 a_1,a_2,\dots,a_n\ (-10^9 \leq a_i \leq 10^9) 表示到达城市1到n可以获得的金币数量(第0个城市无法获得金币)。


输出描述:
\,\,\,\,\,\,\,\,\,\,在一行上输出一个整数表示答案;如果无法到达第 n 个城市,则输出 -1
示例1

输入

10
-1 2 3 4 -9 -9 -1 3 -1 -1

输出

9

说明

最优的方法是:
第 1 步:使用跳跃 3 的卡牌,从 0 跳到 3 ,获得 3 枚金币;
第 2 步:使用跳跃 1 的卡牌,从 3 跳到 4 ,获得 4 枚金币,共有 7 枚金币;
第 3 步:使用跳跃 4 的卡牌,从 4 跳到 8 ,获得 3 枚金币,共有 10 枚金币;
第 4 步:使用跳跃 2 的卡牌,从 8 跳到 10 ,获得 -1 枚金币,共有 9 枚金币。
这道题题目应该要说一句所有测试数据n都是10的倍数不然只能用记忆化收索加剪枝我的剪枝已经很好了但还是只能过16个
import java.util.*;
import java.io.*;
public class Main {
    public static final int MAXN=100001;
    public static long[][][] dp=new long[MAXN][16][2];
    public static long[][] dp1=new long[MAXN][16];
    public static int[] array=new int[MAXN];
    public static int n;
    //记忆化收索
    public static long dfs(int cur,int status,long worth){
        if(cur>n) return Integer.MIN_VALUE;
        if(cur==n&&worth+array[cur]>=0) return array[cur];
        if(worth+array[cur]<0) return Integer.MIN_VALUE;
        if(status==0) status=15;
        if(dp[cur][status][0]!=-2&&dp[cur][status][1]>=worth) return dp[cur][status][0];
        long ans=Integer.MIN_VALUE;
        ArrayList<Integer> list=new ArrayList<>();
        for(int i=0;i<4;i++){
            if((status&(1<<i))!=0){
                if(array[cur+i+1]>=0) ans=Math.max(ans,dfs(cur+i+1,(status^(1<<i)),worth+array[cur]));
                else list.add(i);
            }
        }
        for(int i:list){
            ans=Math.max(ans,dfs(cur+i+1,(status^(1<<i)),worth+array[cur]));
        }
        list.clear();
        dp[cur][status][0]=ans==Integer.MIN_VALUE?Integer.MIN_VALUE:ans+array[cur];
        dp[cur][status][1]=worth;
        return dp[cur][status][0];
    }
    //动态规划版
    public static void dfs1(){
        for(int i=1;i<=n;i++){
            for(int j=0;j<=15;j++){
                long ans=Integer.MIN_VALUE;
                for(int k=0;k<4;k++){
                    if((j&(1<<k))==0&&i>k){
                        ans=Math.max(ans,dp1[i-k-1][(j|(1<<k))==15?0:(j|(1<<k))]);
                    }
                }
                if(ans+array[i]<0) dp1[i][j]=Integer.MIN_VALUE;
                else dp1[i][j]=ans+array[i];
                //System.out.println(i+" "+j+" "+dp1[i][j]);
            }
        }
    }
    public static void main(String[] args) throws IOException{
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
        n=Integer.parseInt(br.readLine());
        String[] str=br.readLine().split(" ");
        array[0]=0;
        for(int i=0;i<n;i++){
            array[i+1]=Integer.parseInt(str[i]);
        }
        for(long[][] P:dp){
            for(long[] P1:P){
                Arrays.fill(P1,-2);
            }
        }
        //dfs(0,15,0);
        dfs1();
        bw.write((dp1[n][0]==Integer.MIN_VALUE?-1:dp1[n][0])+"");
        bw.close();
        br.close();
    }
}
发表于 2025-02-19 00:12:18 回复(0)
public class BigRichGame {
    public static void main(String[] args) {
        int[] cityCoin = {-1, 2, 3, 4, -9, -9, -1, 3, -1, -1, 10, -1, 20};
        int result = getResult(cityCoin);
        if (result == Integer.MIN_VALUE) {
            System.out.println("没有合适的组合到达n城市");
        } else {
            System.out.println("最大金币值:" + result);
        }
    }


    //将数组拆分成很多个10步
    public static int getResult(int[] cityCoin) {
        int[] steps = {1, 2, 3, 4};
        int res = 0;
        int l = cityCoin.length - 1;
        int r = -1;
        while (r < l) {
            int n = Math.min(r + 10, l);
            LinkedList<Integer> roundStep = new LinkedList<>();
            int max = getGoldCoin(cityCoin, r, n, steps, r, roundStep);
            res += max;
            r += 10;
        }
        return res;
    }


    //每十步的最优解
    public static int getGoldCoin(int[] cityCoin, int r, int n, int[] steps, int start, LinkedList<Integer> roundStep) {
        //如果已经到达n城市则不需要再往前,直接返回我所有拿到的值
        if (r == n) {
            return cityCoin[n];
        }

        int max = Integer.MIN_VALUE;

        for (int step : steps) {
            int next = r + step;

            //如果大于n则直接结束
            if (next > n) {
                continue;
            }

            if (roundStep.contains(step)) {
                continue;
            }

            roundStep.add(step);

            int nextAns = getGoldCoin(cityCoin, next, n, steps, start, roundStep);
            int nowAns = r != start ? cityCoin[r] : 0;
            int ans = nextAns == Integer.MIN_VALUE ? Integer.MIN_VALUE : Math.max(max, nowAns + nextAns);
            max = Math.max(ans, max);
            roundStep.removeLast();
        }

        return max;
    }

}

发表于 2025-02-15 20:32:53 回复(0)