洛谷 P1541 烏龜棋
P1541 [NOIP2010 提高組] 烏龜棋
題目背景
小明過生日的時候,爸爸送給他一副烏龜棋當作禮物。
題目描述
烏龜棋的棋盤是一行NN個格子,每個格子上一個分數(非負整數)。棋盤第1格是唯一的起點,第NN格是終點,遊戲要求玩家控制一個烏龜棋子從起點出發走到終點。
烏龜棋中MM張爬行卡片,分成4種不同的型別(MM張卡片中不一定包含所有44種類型的卡片,見樣例),每種型別的卡片上分別標有1,2,3,41,2,3,4四個數字之一,表示使用這種卡片後,烏龜棋子將向前爬行相應的格子數。遊戲中,玩家每次需要從所有的爬行卡片中選擇一張之前沒有使用過的爬行卡片,控制烏龜棋子前進相應的格子數,每張卡片只能使用一次。
遊戲中,烏龜棋子自動獲得起點格子的分數,並且在後續的爬行中每到達一個格子,就得到該格子相應的分數。玩家最終遊戲得分就是烏龜棋子從起點到終點過程中到過的所有格子的分數總和。
很明顯,用不同的爬行卡片使用順序會使得最終遊戲的得分不同,小明想要找到一種卡片使用順序使得最終遊戲得分最多。
現在,告訴你棋盤上每個格子的分數和所有的爬行卡片,你能告訴小明,他最多能得到多少分嗎?
輸入格式
每行中兩個數之間用一個空格隔開。
第11行22個正整數N,MN,M,分別表示棋盤格子數和爬行卡片數。
第22行NN個非負整數,a_1,a_2,…,a_Na1,a2,…,aN,其中a_iai表示棋盤第ii個格子上的分數。
第33行MM個整數,b_1,b_2,…,b_Mb1,b2,…,bM,表示M張爬行卡片上的數字。
輸入資料保證到達終點時剛好用光MM張爬行卡片。
輸出格式
11個整數,表示小明最多能得到的分數。
輸入輸出樣例
輸入 #19 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1
輸出 #1
73
說明/提示
每個測試點1s1s
小明使用爬行卡片順序為1,1,3,1,21,1,3,1,2,得到的分數為6+10+14+8+18+17=736+10+14+8+18+17=73。注意,由於起點是11,所以自動獲得第11格的分數66。
對於30\%30%的資料有1≤N≤30,1≤M≤121≤N≤30,1≤M≤12。
對於50\%50%的資料有1≤N≤120,1≤M≤501≤N≤120,1≤M≤50,且44種爬行卡片,每種卡片的張數不會超過2020。
對於100\%100%的資料有1≤N≤350,1≤M≤1201≤N≤350,1≤M≤120,且44種爬行卡片,每種卡片的張數不會超過4040;0≤a_i≤100,1≤i≤N,1≤b_i≤4,1≤i≤M0≤ai≤100,1≤i≤N,1≤bi≤4,1≤i≤M。
思路:
與藍皮書上的照相排序類似,這裡也是線性dp,狀態表示有很多維~
首先想想這個題狀態怎麼表示,既然只有四種牌,並且每種牌不會超過40,可以開一個四維的陣列來表示狀態,具體表示為,每種牌已經使用的個數f(a,b,c,d)
想要找到的狀態屬性是最大值,所以每次狀態轉移時記得取個max
狀態轉移:將1,2,3,4其中一個牌用掉一張,並且獲取在下一步將要獲得的分數
假如用掉的是牌1,則f = max(f, f[a - 1][b][c][d] + score[...]) 這裡f[a - 1][...]是上一個狀態,也就是轉移前的"未曾使用第一張牌"這個狀態
題解:
/*
************************************
***********emu^w^***********
*/
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
const int P = 13131;
#define ll long long
const int mod = 1E6 + 7;
const int INF = 0x3f, sINF = 0x3f3f3f3f;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
//
const int N = 41;
int f[N][N][N][N];
int card[5], q[400];
int n, m;
int main()
{
cin>>n>>m;
for(int i = 0; i < n; i++) cin>>q[i];
while(m--)
{
int temp;
cin>>temp;
card[temp]++;
}
for(int a = 0; a <= card[1]; a++)
for(int b = 0; b <= card[2]; b++)
for(int c = 0; c <= card[3]; c++)
for(int d = 0; d <= card[4]; d++)
{
int temp = q[a + 2 * b + 3 * c + 4 * d];
int &v = f[a][b][c][d];
v = temp;
if(a) v = max(v, f[a - 1][b][c][d] + temp);
if(b) v = max(v, f[a][b - 1][c][d] + temp);
if(c) v = max(v, f[a][b][c - 1][d] + temp);
if(d) v = max(v, f[a][b][c][d - 1] + temp);
}
cout<<f[card[1]][card[2]][card[3]][card[4]];
}
時間複雜度O(40^4);
附帶一張閆氏dp分析線性dp思維圖