網絡遊戲的玩家策略與公司設計

這是最近看到的一道題,沒有時間來全解,希望可以給你們一些幫助。

題目:某策略型網絡遊戲設置有三種原料礦藏 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


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