數模2020B題穿越沙漠


由於存在外掛標簽,所以更好的閱讀體驗建議前往我的新博客
而且博客園回復我不常看,建議去新博客評論

許久不見動態規划,沒想到數模碰到了,就想水篇久違的題解。

至於為什么不放完整論文?畢竟是當練習做肯定是做的不是很好啦,話說原來數模出題人也會是ACMer嗎

穿越沙漠

題意

​ 考慮如下的小游戲:玩家憑借一張地圖,利用初始資金購買一定數量的水和食物(包括食品和其他日常用品),從起點出發,在沙漠中行走。途中會遇到不同的天氣,也可在礦山、村庄補充資金或資源,目標是在規定時間內到達終點,並保留盡可能多的資金。

游戲的基本規則如下:

(1)以天為基本時間單位,游戲的開始時間為第0天,玩家位於起點。玩家必須在截止日期或之前到達終點,到達終點后該玩家的游戲結束。

(2)穿越沙漠需水和食物兩種資源,它們的最小計量單位均為箱。每天玩家擁有的水和食物質量之和不能超過負重上限。若未到達終點而水或食物已耗盡,視為游戲失敗。

(3)每天的天氣為“晴朗”、“高溫”、“沙暴”三種狀況之一,沙漠中所有區域的天氣相同。

(4)每天玩家可從地圖中的某個區域到達與之相鄰的另一個區域,也可在原地停留。沙暴日必須在原地停留

(5)玩家在原地停留一天消耗的資源數量稱為基礎消耗量,行走一天消耗的資源數量為基礎消耗量的2倍

(6)玩家第0天可在起點處用初始資金以基准價格購買水和食物。玩家可在起點停留或回到起點,但不能多次在起點購買資源。玩家到達終點后可退回剩余的水和食物,每箱退回價格為基准價格的一半

(7)玩家在礦山停留時,可通過挖礦獲得資金,挖礦一天獲得的資金量稱為基礎收益。如果挖礦,消耗的資源數量為基礎消耗量的3倍;如果不挖礦,消耗的資源數量為基礎消耗量。到達礦山當天不能挖礦。沙暴日也可挖礦。

(8)玩家用剩余的初始資金或挖礦獲得的資金在村庄去其他地方是可以購買水和食物,每箱價格為基准價格的2倍

請根據游戲的設定,假設只有一名玩家,在整個游戲時段內每天天氣狀況事先全部已知,試給出一般情況下玩家的最優路徑。

{% tabs 關卡 %}

{%img https://cdn.jsdelivr.net/gh/dummerchen/My_Image_Bed03@image_bed_001/img/20210818172839.png , height=50vh%}

{%img https://cdn.jsdelivr.net/gh/dummerchen/My_Image_Bed03@image_bed_001/img/20210818172646.png , height=50vh%}

{% tip success %}最優解為到終點還有10470金錢{% endtip %}

{%img https://cdn.jsdelivr.net/gh/dummerchen/My_Image_Bed03@image_bed_001/img/20210818172756.png , height=50vh %}

{%img https://cdn.jsdelivr.net/gh/dummerchen/My_Image_Bed03@image_bed_001/img/20210818174449.png , height=50vh%}

{%tip success%}最優解為到終點時還有12730金錢{%endtip%}

{% endtabs %}

思路

很明顯的一個動態規划

設狀態dp[k][j][w][f]代表第k天時在第j個點剩余水為w箱剩余食物為f箱的最大資金,則:

\[ans=max_{w,f,i} \quad dp[k][zd][w][f] \]

就是遍歷第每天在終點的所有水、食物的狀態求最大值。

初始值設定

由於起始點可以在起點購買物資,則有初始狀態:

\[dp[0][qd][w][f]=10000-cost\_water*w-cost\_food*f \quad w \in [0,400] f\in [0,600] \]

其中\(cost\_water\)​​,\(cost\_food\)​​​​ 為購買水和食物消耗的錢。

這里假設起始為第0天,則第一天天氣影響的是從第0天到第1天。

狀態轉移方程

當第k天人在村庄j時:

  • 第k天為沙暴天氣:

    dp[k+1][j][w+ww-xh_water[tq]][f+ff-xh_food[tq]]}=max(dp[k][j][w][f]-2*ww*cost_water-2*ff*cost_food

  • 非沙暴天氣:

    ​ 從j點走到jj點

    dp[k+1][jj][w+ww-xh_water[tq]][f+ff-xh_food[tq]]}=max(dp[k][j][w][f]-2*ww*cost_water-2*ff*cost_food

當第k天人在礦山j時:

  • 挖礦:

    dp[k+1][j][w-dig*xh_water[tq]][f-dig*xh_food[tq]]=max(dp[k][j][w][f]+1000)

  • 第k天為沙暴天氣:

    dp[k+1][j][w-xh_water[tq]][f-xh_food[tq]]=max(dp[k][j][w][f])

  • 第k天為非沙暴天氣:

    dp[k+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]=max(dp[k][jj][w][f])

當第k天人在其他地區時

  • 第k天為沙暴天氣:

    dp[k+1][j][w-xh_water[tq]][f-xh_food[tq]]=max(dp[k][j][w][f])

  • 第k天為非沙暴天氣:

    ​ 從j點走到jj點

    dp[k][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]=max(dp[k][j][w][f])

優化

​ 雖然沒有評測姬,但是作為曾經的Acmer不能容忍運行樣例大於1s,所以只會轉移方程還是過不了這題。

顯然由樣例可知,點 太 多 了!!!,我們考慮刪點。

稍微思考一下就知道這題有幾個隱含條件:

  • 除了回村庄補充物資,不會走回頭路。
  • 除了挖礦和沙塵暴不會在原地停留。
  • 只會走關鍵點之間的最短路徑

故我們只需要將關鍵點之間的最短路求出,最短路經過的點才被認為是有效點,最短路經過的邊才被認為是有效邊,這樣就可以化簡圖了。

化簡之后的路徑圖如下:

image-20210818175743599

​ 可見有效點只有10個大大減少了時間復雜度,但是點數超過13仍會爆空間和時間,空間可以試試滾動數組優化,時間我是沒什么好辦法了。

代碼

第一關代碼

#include<bits/stdc++.h>
#include<iostream>
using namespace std;

// 點數
const int N=11,M=28,inf=0x3f3f3f,Day=30;
int dp[32][N+1][405][605],zd,qd,FZ;
int cost_water,cost_food,walk,dig,buy;
int xh_water[3]={5,8,10},xh_food[3]={7,6,10};
bool cz[N+1],ks[N+1];

struct node
{
    short day; // i 
    short from; // jj j
    int water,food;
    int money;
    bool operator!=(const node &x){
        return x.day!=day || x.from!=from || x.water!=water || x.food!=food ;
    };
}path[31][N+1][405][605],lastpath;
vector <int> weather;
vector <int> g[N];
map <int,int> mp;
void push_back(int x,int y)
{
    g[x].push_back(y);
    g[y].push_back(x);
}

void build_map()
{
    push_back(1,2);
    push_back(2,3);
    push_back(2,5);
    push_back(5,6);
    push_back(3,4);
    push_back(4,7);
    push_back(6,7);
    push_back(7,8);
    push_back(8,9);
    push_back(9,10);
    push_back(10,11);

    mp[1]=1;
    mp[2]=25;
    mp[3]=26;
    mp[4]=27;
    mp[5]=24;
    mp[6]=23;
    mp[7]=21;
    mp[8]=9;
    mp[9]=15;
    mp[10]=14;
    mp[11]=12;
	for(int i=1;i<=N;i++)
    {
        cz[i]=0;
        ks[i]=0;
    }
    cz[9]=1;
    ks[11]=1;
	zd=4;
    qd=1;
    
    return ;
}
void init()
{
    memset(dp,-inf,sizeof(dp));
    FZ=1200;
    cost_water=5;
    cost_food=10;

    walk=2;
    buy=2;
    dig=3;

    
    for(int k=0;k<=405;k++)
    {
        for(int l=0;l<=601;l++)
        {
            if(k*3+l*2<=FZ)
            {
                dp[0][qd][k][l]=10000-k*cost_water-l*cost_food;
            }
        }
    }
    printf("init %d\n",dp[0][1][178][333]);
    path[0][1][0][0]={0,0,0,0};
    return ;
}
int main()
{
    
    weather={
        1,1,0,2,0,1,2,0,1,1,
        2,1,0,1,1,1,2,2,1,1,
        0,0,1,0,2,1,0,0,1,1,
    };
    
    build_map();
    init();
    for(int i=0;i<Day;i++)
    {
        printf("第%d天\n",i);
        int tq=weather[i];
        for(int j=1;j<=N;j++)
        {
            if(cz[j])// 村庄
            {
                for(int w=0;w<=405;w++)
                {
                    for(int f=0;w*3+f*2<=1200;f++)
                    {
                        //購買或不夠買物資(ww=0,ff=0就是不購買) 
                        if(tq==2) //停留
                        {
	                        int money=dp[i][j][w][f];
	                        for(int ww=0;ww<=money/cost_water;ww++)
	                        {
	                            for(int ff=0;ff<=(FZ-(w+ww)*3)/2-f;ff++)
	                            {
                                
                                    if(w+ww-xh_water[tq]>=0&&f+ff-xh_food[tq]>=0&&dp[i][j][w][f]-2*ww*cost_water-2*ff*cost_food>=0)
                                    {
                                        if(dp[i+1][j][w+ww-xh_water[tq]][f+ff-xh_food[tq]]<dp[i][j][w][f]-2*ww*cost_water-2*ff*cost_food)
                                        {
                                            dp[i+1][j][w+ww-xh_water[tq]][f+ff-xh_food[tq]]=dp[i][j][w][f]-2*ww*cost_water-2*ff*cost_food;
                                            path[i+1][j][w+ww-xh_water[tq]][f+ff-xh_food[tq]]={i,j,w,f,dp[i][j][w][f]-2*ww*cost_water-2*ff*cost_food};
                                        }
                                    }

                                }
                            }
                        }
                        else //從j走到jj
                        {
                            for(auto jj:g[j])
                            {
                            	int money=dp[i][j][w][f];
		                        for(int ww=0;ww<=money/cost_water;ww++)
		                        {
		                            for(int ff=0;ff<=(FZ-(w+ww)*3)/2-f;ff++)
		                            {
		                                if(w+ww-walk*xh_water[tq]>=0&&f+ff-walk*xh_food[tq]>=0&&dp[i][j][w][f]-buy*ww*cost_water-buy*ff*cost_food>=0)
		                                {
		                                    if(dp[i+1][jj][w+ww-walk*xh_water[tq]][f+ff-walk*xh_food[tq]]<dp[i][j][w][f]-buy*ww*cost_water-buy*ff*cost_food)
		                                    {
		                                        dp[i+1][jj][w+ww-walk*xh_water[tq]][f+ff-walk*xh_food[tq]]=dp[i][j][w][f]-buy*ww*cost_water-buy*ff*cost_food;
		                                        path[i+1][jj][w+ww-walk*xh_water[tq]][f+ff-walk*xh_food[tq]]={i,j,w,f,dp[i][j][w][f]-buy*ww*cost_water-buy*ff*cost_food};
		                                    }
		                                    
		                                }
		                            }
		                        }
                            }
                        }
                    }
                }
            }
            else if (ks[j])// 礦山
            {
                for(int w=0;w<=405;w++)
                {
                    for(int f=0;w*3+f*2<=1200;f++)
                    {
                        // 已經停留一天了,可以挖礦
                        if(w-dig*xh_water[tq]>=0&&f-dig*xh_food[tq]>=0)
                        {
                            if(dp[i+1][j][w-dig*xh_water[tq]][f-dig*xh_food[tq]]<dp[i][j][w][f]+1000&&dp[i][j][w][f]>=0)
                            {
                                dp[i+1][j][w-dig*xh_water[tq]][f-dig*xh_food[tq]]=dp[i][j][w][f]+1000;
                                path[i+1][j][w-dig*xh_water[tq]][f-dig*xh_food[tq]]={i,j,w,f,dp[i][j][w][f]+1000};
                            }
                        
                        }
                        // 在礦山不挖礦或 不允許挖礦
                        if(tq==2) //停留但不挖礦
                        {
                            if(w-xh_water[tq]>=0&&f-xh_food[tq]>=0)
                            {
                                if(dp[i+1][j][w-xh_water[tq]][f-xh_food[tq]]<dp[i][j][w][f]&&dp[i][j][w][f]>=0)
                                {

                                    dp[i+1][j][w-xh_water[tq]][f-xh_food[tq]]=dp[i][j][w][f];
                                    path[i+1][j][w-xh_water[tq]][f-xh_food[tq]]={i,j,w,f,dp[i][j][w][f]};
                                }
                        
                            }
                        }
                        else
                        {
                            if(w-walk*xh_water[tq]>=0&&f-walk*xh_food[tq]>=0)
                            {
                                for(auto jj:g[j])
                                {
                                    if(dp[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]<dp[i][j][w][f]&&dp[i][j][w][f]>=0)
                                    {
                                        dp[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]=dp[i][j][w][f];
                                        path[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]={i,j,w,f,dp[i][j][w][f]};
                                    }
                                
                                }
                            }
                        }
                    }
                }
            }
            else //普通區
            {
                for(int w=0;w<=405;w++)
                {
                    for(int f=0;w*3+f*2<=1200;f++)
                    {
                        if(tq==2) //在j點停留
                        {
                            if(w-xh_water[tq]>=0&&f-xh_food[tq]>=0&&dp[i][j][w][f]>=0)
                            {
                                if(dp[i+1][j][w-xh_water[tq]][f-xh_food[tq]]<dp[i][j][w][f])
                                {
                                    dp[i+1][j][w-xh_water[tq]][f-xh_food[tq]]=dp[i][j][w][f];
                                    path[i+1][j][w-xh_water[tq]][f-xh_food[tq]]={i,j,w,f,dp[i][j][w][f]};
                                }
                            }
                        }
                        else// 走到jj點
                        {
                            for(auto jj:g[j])
                            {
                                if(w-walk*xh_water[tq]>=0&&f-walk*xh_food[tq]>=0&&dp[i][j][w][f]>=0)
                                {
                                    if(dp[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]<dp[i][j][w][f])
                                    {
                                        
                                        dp[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]=dp[i][j][w][f];
                                        path[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]={i,j,w,f,dp[i][j][w][f]};

                                    }
                                
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    int ans=-inf;
    node lastpath;
    int last_water=0,last_food=0,last_day=Day;
    for(int i=0;i<=Day;i++)
    {
        for(int w=0;w<=405;w++)
            for(int f=0;w*3+2*f<=1200;f++)
            {
                if(dp[i][zd][w][f]>ans)
                {
                    ans=dp[i][zd][w][f];
                    lastpath=path[i][zd][w][f];
                	last_water=w;
                	last_food=f;
                	last_day=i;
				}
            }
    }
    stack<node> s;
    stack<int> my;
    printf("??day:%d weather:%d %d water:%d food:%d money:%d\n",last_day,weather[Day],zd,last_water,last_food,ans);
    s.push((node){last_day,zd,last_water,last_food,ans});
    
    
	while(lastpath!=path[0][1][0][0])
    {
        s.push(lastpath);
        printf("??day:%d weather:%d %d water:%d food:%d money:%d\n",lastpath.day,weather[lastpath.day],mp[lastpath.from],lastpath.water,lastpath.food,lastpath.money);
		my.push(lastpath.money);
        lastpath=path[lastpath.day][lastpath.from][lastpath.water][lastpath.food];
    }
    freopen("output.txt","w",stdout);
    my.push(my.top());
    while (!s.empty())
    {
        node t=s.top();
        int money=my.top();
        printf("Day:%d weather:%d point:%d water:%d food:%d money:%d\n",t.day,weather[t.day],mp[t.from],t.water,t.food,money);
        s.pop();
        my.pop();
    }
    printf("%d\n",ans);
    return 0;
}

第二關代碼

​ 與第一關不同的是點的數量變多了,空間復雜度過不去。我只好把path刪了一個變量money才勉強過去。就是后面要手算money很麻煩

​ 后來想應該可以滾動數組的,但是不想寫了。畢竟已經退役了

#include<bits/stdc++.h>
#include<iostream>
using namespace std;

const short N=27,inf=20000,Day=30;
short dp[31][N+1][401][601],zd,qd,FZ;
short cost_water,cost_food,walk,dig,buy;
short xh_water[3]={5,8,10},xh_food[3]={7,6,10};
bool cz[N+1],ks[N+1];

struct node
{
    char day; // i 
    char from; // jj j
    short water,food;
    bool operator!=(const node &x){
        return (x.day-'0')!=(day-'0') || (x.from-'0'!=from-'0') || (x.water-'0')!=(water-'0') || (x.food-'0'!=food-'0') ;
    };
}path[31][N+1][401][601],lastpath;
vector <short> weather;
vector <short> g[N+1];
map <short,short> mp;
void push_back(short x,short y)
{
    g[x].push_back(y);
    g[y].push_back(x);
}

void build_map(short flag)
{
    if(flag==2)
    {
    	push_back(1,2);
        push_back(2,3);
        push_back(3,4);
        push_back(4,5);
        push_back(5,6);
        push_back(6,7);
        push_back(7,8);
        push_back(8,9);
        push_back(9,10);
        push_back(10,11);
        push_back(11,12);
        push_back(7,13);
        push_back(13,14);
        push_back(14,15);
        push_back(15,16);
        push_back(15,10);
        push_back(15,11);
        push_back(16,12);
        push_back(3,17);
        push_back(17,18);
        push_back(18,19);
        push_back(19,20);
        push_back(20,21);
        push_back(21,22);
        push_back(22,23);
        push_back(15,23);
        push_back(23,16);

        mp[1]=1;
        mp[2]=2;
        mp[3]=3;
        mp[4]=4;
        mp[5]=12;
        mp[6]=21;
        mp[7]=29;
        mp[8]=30;
        mp[9]=39;
        mp[10]=47;
        mp[11]=56;
        mp[12]=64;
        mp[13]=38;
        mp[14]=46;
        mp[15]=55;
        mp[16]=63;
        mp[17]=11;
        mp[18]=20;
        mp[19]=28;
        mp[20]=37;
        mp[21]=45;
        mp[22]=54;
        mp[23]=62;
        for(short i=1;i<=N;i++)
        {
            cz[i]=0;
            ks[i]=0;
        }
        cz[9]=cz[23]=1;
        ks[8]=ks[15]=1;
        qd=1;
        zd=12;
	}
    return ;
}

void init()
{
	
    FZ=1200;
    cost_water=5;
    cost_food=10;

    walk=2;
    buy=2;
    dig=3;
	for(short i=0;i<=Day;i++)
	{
		for(short j=1;j<=N;j++)
		{
			for(short w=0;w<=400;w++)
			{
				for(short f=0;f<=600;f++)
				{
					if(w*3+f*2<=FZ)
					{
						dp[i][j][w][f]=-inf;
					}
				}
			}
		}
	}
    for(short k=10;k<=405;k++)
    {
        for(short l=0;k*3+l*2<=FZ;l++)
        {
    		dp[0][qd][k][l]=10000-k*cost_water-l*cost_food;
        }
    }
    path[0][1][0][0]={0,0,0,0};
    return ;
}

int main()
{
    
    weather={
        1,1,0,2,0,1,2,0,1,1,
        2,1,0,1,1,1,2,2,1,1,
        0,0,1,0,2,1,0,0,1,1,
    };
    
    build_map(2);
    init();
    // dp [i][j][w][f]
    // 第i天 在j個點 w 箱水 f 箱食物 時最大利潤,
    // max_k_l (dp[30][27][k][l])
    // 第i天的天氣決定 i+1天能否移動
    // 如:第0天天氣決定第1天能否移動

    // 先不考慮非礦山停留自願停留情況
    // for(short i=1;i<N;i++)
    // {
    //     printf("第%d個點",i);
    //     for(auto j:mp[i]) 
    //     {
    //         printf("%d ",j);
    //     }
    //     printf("\n");
    // }
    // printf("???%d %d %d %d\n",xh_food[0],xh_food[2],xh_water[0],xh_water[1]);
    for(short i=0;i<Day;i++)
    {
        printf("第%d天\n",i);
        short tq=weather[i];
        for(short j=1;j<=N;j++)
        {
            if(cz[j])// 村庄
            {
                for(short w=0;w<=405;w++)
                {
                    for(short f=0;w*3+f*2<=1200;f++)
                    {
                        //購買或不夠買物資(ww=0,ff=0就是不購買) 
                        if(tq==2) //停留
                        {
	                        short money=dp[i][j][w][f];
	                        for(short ww=0;ww<=money/cost_water;ww++)
	                        {
	                            for(short ff=0;ff<=(FZ-(w+ww)*3)/2-f;ff++)
	                            {
                                
                                    if(w+ww-xh_water[tq]>=0&&f+ff-xh_food[tq]>=0&&dp[i][j][w][f]-2*ww*cost_water-2*ff*cost_food>=0)
                                    {
                                        if(dp[i+1][j][w+ww-xh_water[tq]][f+ff-xh_food[tq]]<dp[i][j][w][f]-2*ww*cost_water-2*ff*cost_food)
                                        {
                                            dp[i+1][j][w+ww-xh_water[tq]][f+ff-xh_food[tq]]=dp[i][j][w][f]-2*ww*cost_water-2*ff*cost_food;
                                            // path[i+1][j][w+ww-xh_water[tq]][f+ff-xh_food[tq]]={i,j,w,f,dp[i][j][w][f]-2*ww*cost_water-2*ff*cost_food};
                                            path[i+1][j][w+ww-xh_water[tq]][f+ff-xh_food[tq]]={i,j,w,f};
                                        }
                                    }

                                }
                            }
                        }
                        else //從j走到jj
                        {
                            for(auto jj:g[j])
                            {
                            	short money=dp[i][j][w][f];
		                        for(short ww=0;ww<=money/cost_water;ww++)
		                        {
		                            for(short ff=0;ff<=(FZ-(w+ww)*3)/2-f;ff++)
		                            {
		                                if(w+ww-walk*xh_water[tq]>=0&&f+ff-walk*xh_food[tq]>=0&&dp[i][j][w][f]-buy*ww*cost_water-buy*ff*cost_food>=0)
		                                {
		                                    if(dp[i+1][jj][w+ww-walk*xh_water[tq]][f+ff-walk*xh_food[tq]]<dp[i][j][w][f]-buy*ww*cost_water-buy*ff*cost_food)
		                                    {
		                                        dp[i+1][jj][w+ww-walk*xh_water[tq]][f+ff-walk*xh_food[tq]]=dp[i][j][w][f]-buy*ww*cost_water-buy*ff*cost_food;
		                                        // path[i+1][jj][w+ww-walk*xh_water[tq]][f+ff-walk*xh_food[tq]]={i,j,w,f,(short)dp[i][j][w][f]-buy*ww*cost_water-buy*ff*cost_food};
		                                        path[i+1][jj][w+ww-walk*xh_water[tq]][f+ff-walk*xh_food[tq]]={i,j,w,f};
		                                    }
		                                    
		                                }
		                            }
		                        }
                            }
                        }
                    }
                }
            }
            else if (ks[j])// 礦山
            {
                for(short w=0;w<=405;w++)
                {
                    for(short f=0;w*3+f*2<=1200;f++)
                    {
                        // 已經停留一天了,可以挖礦
                        if(w-dig*xh_water[tq]>=0&&f-dig*xh_food[tq]>=0)
                        {
                            if(dp[i+1][j][w-dig*xh_water[tq]][f-dig*xh_food[tq]]<dp[i][j][w][f]+1000&&dp[i][j][w][f]>=0)
                            {
                                dp[i+1][j][w-dig*xh_water[tq]][f-dig*xh_food[tq]]=dp[i][j][w][f]+1000;
//                                path[i+1][j][w-dig*xh_water[tq]][f-dig*xh_food[tq]]={i,j,w,f,(short)dp[i][j][w][f]+1000};
                                path[i+1][j][w-dig*xh_water[tq]][f-dig*xh_food[tq]]={i,j,w,f};
                            }
                        
                        }
                        // 在礦山不挖礦或 不允許挖礦
                        if(tq==2) //停留但不挖礦
                        {
                            if(w-xh_water[tq]>=0&&f-xh_food[tq]>=0)
                            {
                                if(dp[i+1][j][w-xh_water[tq]][f-xh_food[tq]]<dp[i][j][w][f]&&dp[i][j][w][f]>=0)
                                {

                                    dp[i+1][j][w-xh_water[tq]][f-xh_food[tq]]=dp[i][j][w][f];
                                    // path[i+1][j][w-xh_water[tq]][f-xh_food[tq]]={i,j,w,f,dp[i][j][w][f]};
                                    path[i+1][j][w-xh_water[tq]][f-xh_food[tq]]={i,j,w,f};
                                }
                        
                            }
                        }
                        else
                        {
                            if(w-walk*xh_water[tq]>=0&&f-walk*xh_food[tq]>=0)
                            {
                                for(auto jj:g[j])
                                {
                                    if(dp[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]<dp[i][j][w][f]&&dp[i][j][w][f]>=0)
                                    {
                                        dp[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]=dp[i][j][w][f];
                                        // path[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]={i,j,w,f,dp[i][j][w][f]};
                                        path[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]={i,j,w,f};
                                    }
                                
                                }
                            }
                        }
                    }
                }
            }
            else //普通區
            {
                for(short w=0;w<=405;w++)
                {
                    for(short f=0;w*3+f*2<=1200;f++)
                    {
                        if(tq==2) //在j點停留
                        {
                            if(w-xh_water[tq]>=0&&f-xh_food[tq]>=0&&dp[i][j][w][f]>=0)
                            {
                                if(dp[i+1][j][w-xh_water[tq]][f-xh_food[tq]]<dp[i][j][w][f])
                                {
                                    dp[i+1][j][w-xh_water[tq]][f-xh_food[tq]]=dp[i][j][w][f];
                                    // path[i+1][j][w-xh_water[tq]][f-xh_food[tq]]={i,j,w,f,dp[i][j][w][f]};
                                    path[i+1][j][w-xh_water[tq]][f-xh_food[tq]]={i,j,w,f};
                                }
                            }
                        }
                        else// 走到jj點
                        {
                            for(auto jj:g[j])
                            {
                                if(w-walk*xh_water[tq]>=0&&f-walk*xh_food[tq]>=0&&dp[i][j][w][f]>=0)
                                {
                                    if(dp[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]<dp[i][j][w][f])
                                    {
                                        
                                        dp[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]=dp[i][j][w][f];
                                        // path[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]={i,j,w,f,dp[i][j][w][f]};
                                        path[i+1][jj][w-walk*xh_water[tq]][f-walk*xh_food[tq]]={i,j,w,f};

                                    }
                                
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    short ans=-inf;
    node lastpath;
    short last_water=0,last_food=0,last_day=Day;
    for(short i=0;i<=Day;i++)
    {
        for(short w=0;w<=405;w++)
            for(short f=0;w*3+2*f<=1200;f++)
            {
                if(dp[i][zd][w][f]>ans)
                {
                    ans=dp[i][zd][w][f];
                    lastpath=path[i][zd][w][f];
                	last_water=w;
                	last_food=f;
                	last_day=char(i);
				}
            }
    }
    stack<node> s;
//    freopen("outputQ2.txt","w",stdout);
    printf("ans:%d\n",ans);
    printf("day:%d weather:%d point:%d water:%d food:%d\n",last_day,weather[Day],zd,last_water,last_food);
    
    node temppath=(node){last_day,zd,last_water,last_food};
    s.push(temppath);
    
	while(lastpath!=path[0][1][0][0])
    {
        s.push(lastpath);
        printf("day:%d weather:%d point %d water:%d food:%d\n",lastpath.day,(int)weather[lastpath.day],(int)mp[lastpath.from],lastpath.water,lastpath.food);
        temppath=lastpath;
        lastpath=path[lastpath.day][lastpath.from][lastpath.water][lastpath.food];
    }
}

末尾的難度嗶嗶

從oi來看的話我個人認為單純dp應該有提高+難度?但是考慮到優化復雜度應該有黑題左右的難度了。我是有什么資格評價的哇

從ACM來看的話如果有時間限制的話應該是個銀牌題吧,沒有時間限制就是個銅牌題。本菜雞做了大半天…


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM