poj2738 Two Ends

題目

題目大意:兩個人玩遊戲,一些牌排成一行,當前玩家可以從最左端或者最右端拿一張牌,第一個人永遠選擇最優的方案,第二個人總是貪心的拿當前牌堆左右兩端更大的,求最後第一個人拿的數字之和比第二個人大多少。

解題思路:題意和當時科創月賽的題很像,月賽時兩個人都是選擇最優方案。當時不懂dp(現在也只是初學),現在看來記憶化處理即可。對於每次拿牌,第一個人總是選擇最優方案,因此可以搜索一下,即左右都拿,遞歸,記錄下來;對於第二個人,只要枚舉兩種情況:左邊更大or右邊更大即可。這樣就是一個記憶化搜索的過程。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 1010;
int num[N];
long long dp[N][N];
long long compute(int l,int r)
{
    if(dp[l][r]!=0){
        //cout<<r<<" "<<l<<endl;
        return dp[l][r];
    }
    if(r-l<=1){
        //cout<<r<<" "<<l<<endl;
        dp[l][r]=abs(num[r]-num[l]);
        return dp[l][r];
    }
    else{
        int ansl,ansr;
        ansl=num[l],ansr=num[r];
        if(num[l+1]>=num[r]){
            ansl+=compute(l+2,r)-num[l+1];
        }
        else{
            ansl+=compute(l+1,r-1)-num[r];
        }
        if(num[l]>=num[r-1]){
            ansr+=compute(l+1,r-1)-num[l];
        }
        else{
            ansr+=compute(l,r-2)-num[r-1];
        }
        dp[l][r]=max(ansl,ansr);
    }
    return dp[l][r];
}
int main()
{
    int n;
    int cnt=1;
    while(~scanf("%d",&n) && n!=0){
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            scanf("%d",&num[i]);
        }
        long long ans=compute(1,n);
        printf("In game %d, the greedy strategy might lose by as many as %lld points.\n",cnt++,ans);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章