這是最近看到的一道題,沒有時間來全解,希望可以給你們一些幫助。
題目:某策略型網絡遊戲設置有三種原料礦藏 I, II, III 和三種功能建築A, B, C。礦藏和建築有1~10 共10 個等級。初始時所有玩家各礦藏和建築的等級均爲1,礦藏和建築升級所需原料種類和數量如表1所示,升級過程可在瞬時完成。各等級的三種礦藏在每小時末可產生的原料數量如表2所示。(選自浙江大學2018數模)
1. 若希望在最短時間內將 A, B, C 三種建築分別升級至i, j, k 級,其中 2<i,j,k<10.玩家應採取怎樣的升級策略。表 1 :礦藏和建築升級所需原料種類和數量
表2 :礦藏每小時產生的原料數量
分析問題,不難發現,這是一道動態規劃的題目。
何爲動態規劃?
用通俗一點的話來說就是“邊走邊看”,注意和回溯法這種先把一條道走到黑的方法區別開來,總的來說就是前面的知道了,後面的也可以根據前面的推導出來了。好了通俗的話說到這了,下面用正規一點的語言總結一下:每次決策依賴於當前狀態,又隨即引起狀態的轉移。一個決策序列就是在變化的狀態中產生出來的,所以,這種多階段最優化決策解決問題的過程就稱爲動態規劃。
一般情況需滿足以下要求:
最優化原理:如果問題的最優解所包含的子問題的解也是最優的,就稱該問題具有最優子結構,即滿足最優化原理。
無後效性:即某階段狀態一旦確定,就不受這個狀態以後決策的影響。也就是說,某狀態以後的過程不會影響以前的狀態,只與當前狀態有關。
有重疊子問題:即子問題之間是不獨立的,一個子問題在下一階段決策中可能被多次使用到。(該性質並不是動態規劃適用的必要條件,但是如果沒有這條性質,動態規劃算法同其他算法相比就不具備優勢
注意:在一些特殊情況也是可以採用動態分析的。
動態規劃方法要尋找符合“最優子結構“的狀態和狀態轉移方程的定義,在找到之後,這個問題就可以以“記憶化地求解遞推式”的方法來解決。而尋找到的定義,纔是動態規劃的本質。
動態規劃在遊戲方面在表現爲當前有限的資源下,製造最強戰鬥力,從而選擇對於總價值最高的建設方式,儘快提升城市的繁榮程度。個人感覺這一代的AI比上一代的AI明顯會思考了很多,而且發展也快了很多。當然遊戲裏面肯定設計複雜很多,所以說AI的設計真的是一個很大的研究方向,總之應該設計這樣的AI,會簡單模擬人的思考。用最少的資源,儘快建設城市,訓練部隊(這兩者怎麼取捨,這也是一個大問題),而且這些還用到了一些博弈論裏面的知識!
解題思路:
最優化結構:初始狀態→│決策1│→│決策2│→…→│決策n│→結束狀態
在動態規劃中我們要做的,就是用遞歸方法找到這種“最優子結構”。
如果我們所列的等式右邊不會用到下標大於左邊i或者k的值,這是"無後效性"的通俗上的數學定義,符合這種定義的狀態定義,我們可以說它具有“最優子結構”的性質(具體詳見參考代碼)
文獻:
如需深入瞭解動態規劃,可參考 http://www.docin.com/p-304455887.html
如需深入瞭解動態規劃的“揹包法”,可參考https://blog.csdn.net/qq_36303472/article/details/68935954
如需瞭解動態規劃的建模方法,可參考https://blog.csdn.net/cytzrs/article/details/50351879
此題可詳見參考代碼。
#include <cstdio>
#include <iostream>
#include <string.h>
#include <math.h>
using namespace std;
const int INF=1000000;
double v[11]={INF,60,120,180,240,300,360,420,480,540,600};
double cost[5][11]={{0,0,0,0,0,0,0,0,0,0,0},
{0,0,830,1630,4900,14700,51300,97100,194200,388000,776000},
{0,0,660,1320,2600,5200,9200,16900,38000,76000,228000},
{0,0,960,2880,5670,8640,17280,51840,86500,173000,519000},
{0,0,2300,6900,13800,27650,51840,89800,137100,274000,810000}};
int maxi(int a,int b,int c)
{
int d=a;
if(b>d) d=b;
if(c>d) d=c;
return d;
}
int mini(int a,int b,int c)
{
int d=a;
if(b<d) d=b;
if(c<d) d=c;
return d;
}
int main()
{
int a,b,c,ii,jj,kk,t_min=INF,cnt=0;
double sum_a=0,sum_b=0,sum_c=0;
int f[11][11][11];
double remain_1[11][11][11],remain_2[11][11][11],remain_3[11][11][11];
int order[11][11][11],stack[30];
cout<<"請輸入建築目標等級:"<<endl;
cin>>a>>b>>c;
for(int i=2;i<=a;i++)
sum_a+=cost[2][i];//建築A升級一共需要的I材料
for(int i=2;i<=b;i++)
sum_b+=cost[3][i];//建築B升級一共需要的II材料
for(int i=2;i<=c;i++)
sum_c+=cost[4][i];//建築III升級一共需要的III材料
memset(f,INF,sizeof(f));
f[1][1][1]=0;
memset(remain_1,0,sizeof(remain_1));
memset(remain_2,0,sizeof(remain_2));
memset(remain_3,0,sizeof(remain_3));
memset(order,0,sizeof(order));
for(int i=1;i<=10;i++)
for(int j=1;j<=10;j++)
for(int k=1;k<=10;k++)//
{
if(i+j+k==3)
continue;
f[i][j][k]=mini(f[i-1][j][k]+ceil((cost[1][i]-remain_1[i-1][j][k])/v[i-1]),f[i][j-1][k]+ceil((cost[1][j]-remain_1[i][j-1][k])/v[i]),f[i][j][k-1]+ceil((cost[1][k]-remain_1[i][j][k-1])/v[i]));
if(f[i][j][k]==f[i-1][j][k]+ceil((cost[1][i]-remain_1[i-1][j][k])/v[i-1]))
{
remain_1[i][j][k]=remain_1[i-1][j][k]+ceil((cost[1][i]-remain_1[i-1][j][k])/v[i-1])*v[i-1]-cost[1][i];
remain_2[i][j][k]=remain_2[i-1][j][k]+ceil((cost[1][i]-remain_1[i-1][j][k])/v[i-1])*v[j];
remain_3[i][j][k]=remain_3[i-1][j][k]+ceil((cost[1][i]-remain_1[i-1][j][k])/v[i-1])*v[k];
order[i][j][k]=1;
}
else if(f[i][j][k]==f[i][j-1][k]+ceil((cost[1][j]-remain_1[i][j-1][k])/v[i]))
{
remain_1[i][j][k]=remain_1[i][j-1][k]+ceil((cost[1][j]-remain_1[i][j-1][k])/v[i])*v[i]-cost[1][j];
remain_2[i][j][k]=remain_2[i][j-1][k]+ceil((cost[1][j]-remain_1[i][j-1][k])/v[i])*v[j-1];
remain_3[i][j][k]=remain_3[i][j-1][k]+ceil((cost[1][j]-remain_1[i][j-1][k])/v[i])*v[k];
order[i][j][k]=2;
}
else
{
remain_1[i][j][k]=remain_1[i][j][k-1]+ceil((cost[1][k]-remain_1[i][j][k-1])/v[i])*v[i]-cost[1][k];
remain_2[i][j][k]=remain_2[i][j][k-1]+ceil((cost[1][k]-remain_1[i][j][k-1])/v[i])*v[j];
remain_3[i][j][k]=remain_3[i][j][k-1]+ceil((cost[1][k]-remain_1[i][j][k-1])/v[i])*v[k-1];
order[i][j][k]=3;
}
}
for(int i=1;i<=10;i++)
for(int j=1;j<=10;j++)
for(int k=1;k<=10;k++)
{
f[i][j][k]+=maxi(ceil((sum_a-remain_1[i][j][k])/v[i]),ceil((sum_b-remain_2[i][j][k])/v[j]),ceil((sum_c-remain_3[i][j][k])/v[k]));
if(f[i][j][k]<t_min)
{
t_min=f[i][j][k];
ii=i;
jj=j;
kk=k;
}
}
while(ii+jj+kk!=3)
{
stack[cnt++]=order[ii][jj][kk];
if(order[ii][jj][kk]==1)
ii--;
else if(order[ii][jj][kk]==2)
jj--;
else
kk--;
}
cout<<"升級序列:"<<endl;
for(int i=cnt-1;i>=0;i--)
cout<<stack[i]<<" ";
cout<<endl;
return 0;
}
代碼來源:https://download.csdn.net/download/liuyifei825/10189049