【bzoj 1806/CS 1801】礦工配餐 IOI2007(五維DP+滾動數組)


樓下是傳送門:
http://www.lydsy.com/JudgeOnline/problem.php?id=1806

Description

現有兩個煤礦,每個煤礦都僱用一組礦工。採煤工作很辛苦,所以礦工們需要良好飲食。每當一輛食品車到達煤礦時,礦工們便會產出一定數量的煤。有三種類型的食品車:肉車,魚車和麪包車。 礦工們喜歡變化的食譜。如果提供的食品能夠不斷變化,他們的產煤量將會增加。每當一個新的食品車到達煤礦時,礦工們就會比較這種新的食品和前兩次(或者少於兩次,如果前面運送食品的次數不足兩次)的食品,並且: • 如果這幾次食品車都是同一類型的食品,則礦工們產出一個單位的煤。 • 如果這幾次食品車中有兩種不同類型的食品,則礦工們產出兩個單位的煤。 • 如果這幾次食品車中有三種不同類型的食品,則礦工們產出三個單位的煤。 預先已知食品車的類型及其被配送的順序。通過確定哪車食品送到哪個煤礦可以影響產煤量。食品車不能被拆分,每個食品車必須被全部送到一個或另一個煤礦。兩個煤礦也並不要求接收相同數量的食品車(事實上,也允許將所有食品車都送到一個煤礦)。 任務 給出食品車的類型及其被配送的順序,要求你寫一個程序,確定哪個食品車應被送到煤礦1,哪個食品車應被送到煤礦2,以使得兩個煤礦的產煤量的總和最大。

Input

輸入的第一行包含一個整數N (1 ≤ N ≤ 100 000), 表示食品車的數目。 第二行包含一個由N個字符組成的字符串,按照配送順序依次表示食品車配送的食品的類型。每個字符是以下三個大寫字母之一:’M’ (表示肉類), ‘F’ (表示魚類) 或 ‘B’ (表示麪包)。

Output

輸出一個整數,表示最大的總產煤量。 評分 在45分的測試數據中,食品車的數目至多爲20

Sample Input

6
MBMFFB

Sample Output

12

思路


五維DP只要不是很喪病,一般就是第一維枚舉位置狀態,第二三維表示第一個情況的選擇狀態,第四五維表示第二個情況的選擇狀態,最終用總的狀態求解
多用於求相同的兩者的符合題意狀態之和的最大或最小值
在本題中第一位枚舉的是第幾輛車,二三維是第一個礦洞,四五維是第二個礦洞,分表表示了數量和狀態
開始的時候預處理一下每個種類以避免重複等等,接着用一個check函數,判斷是否滿足題目中給定的條件
最後進行dp比較取更大的作爲答案
能水過Codevs的數據的TLE…..
http://codevs.cn/problem/1801/
代碼如下:

//TLE
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
#define ri register int
const int sz = 1000010;
inline void read(int &x){
    x=0;bool fl=0;char c=getchar();
    while(c<'0'||c>'9')
    {if(c=='-') fl=1;c=getchar();}
    while(c>='0'&&c<='9')
    {x=x*10+c-'0';c=getchar();}
    if(fl) x*=-1;
}
inline int check(int a,int b,int c)
{
    if(a==0&&b==0) return 1;
    if(a==0) return 1+(b!=c);//代表如果b!=c返回1 
    if(a==b&&b==c) return 1;
    if(a==b||b==c||a==c) return 2;
    return 3;
}
int t[sz],n,f[sz][4][4][4][4];
char s[sz];
int dp(int pos,int a,int b,int x,int y)
{
    if(pos==n+1) return 0;
    if(f[pos][a][b][x][y]!=-1)
        return f[pos][a][b][x][y];
    return f[pos][a][b][x][y]=max(dp(pos+1,b,t[pos],x,y)+check(a,b,t[pos]),dp(pos+1,a,b,y,t[pos])+check(x,y,t[pos]));
}
int main()
{
    read(n);
    scanf("%s",s);
    for(ri i=0;i<n;++i)//!從0開始讀 
        if( s[i] == 'B' ) t[i+1] = 1;
        else if( s[i] == 'M' ) t[i+1] = 2;
        else t[i + 1] = 3;
    memset(f,-1,sizeof(f));
    cout<<dp(1,0,0,0,0);
    return 0;
}


但是上面的只能水過10000的數據,對於加強的100000數據無可奈何,慘遭三遍TLE,各種優化卡常獻祭秒數卻還是難以逃脫這一點
最後各種淚奔直到看到黃學長博客裏記錄%%%
http://hzwer.com/3645.html
“dp加個滾動數組就差不多了”
潯陽 DP 無滾動,一句驚醒夢中人;
垂死病中驚坐起,談笑風生又一年
這裏的f[i][a1][a2][b1][b2]表示發放第i份食品後第一礦洞最近的食品爲 a1 a2,b1 b2同理,讀入的時候判斷成爲什麼值,具體的check還是要具題目來自己分析分析,畢竟這個還是比較好弄的
代碼如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline void read(int &x){
    x=0;bool fl=1;char c=getchar();
    while(c<'0'||c>'9')
    {if(c=='-') fl=-1;c=getchar();}
    while(c>='0'&&c<='9')
    {x=x*10+c-'0';c=getchar();}
    x*=fl;
}
char ch[100010];
int f[5][4][4][4][4],ans,n;
inline int getint(char c)
{
    if(c=='M')return 1;
    else if(c=='F')return 2;
    else return 3;
}
inline int check(int a,int b,int c)
{
    if(a==0&&b==0) return 1;
    if(a==0) return 1+(b!=c);//代表如果b!=c返回1 
    if(a==b&&b==c) return 1;
    if(a==b||b==c||a==c) return 2;
    return 3;
}
int main()
{
    memset(f,-1,sizeof(f));
    f[0][0][0][0][0]=0;
    read(n);
    scanf("%s",ch);
    for(int i=0;i<n;i++)
     for(int a1=0;a1<=3;a1++)
      for(int a2=0;a2<=3;a2++)
       for(int b1=0;b1<=3;b1++)
        for(int b2=0;b2<=3;b2++)
        {
            int x=i%4,y=(i+1)%4;
            if(f[x][a1][a2][b1][b2]==-1)
                continue;
            int t=getint(ch[i]),add;
            add=check(a1,a2,t);
                f[y][a2][t][b1][b2]=
                max(f[y][a2][t][b1][b2],f[x][a1][a2][b1][b2]+add);
            add=check(b1,b2,t);
                f[y][a1][a2][b2][t]=
                max(f[y][a1][a2][b2][t],f[x][a1][a2][b1][b2]+add);
        }
    for(int a1=0;a1<=3;a1++)
     for(int a2=0;a2<=3;a2++)
      for(int b1=0;b1<=3;b1++)
       for(int b2=0;b2<=3;b2++)
        ans=max(ans,f[n%4][a1][a2][b1][b2]);//滾啊滾找回失去的時間【霧】
    printf("%d",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章