1. 程式人生 > >【演算法筆記】資源分配類動態規劃

【演算法筆記】資源分配類動態規劃

1.HLOJ#411機器分配

要求資源分配的最大值,我們可以用二維陣列f[i][j]來表示前i個公司得到j臺機器後所得到的最大盈利值。

方程是:

f[i][j]=max(f[i][j],f[i-1][k]+a[i][j-k]);

我們要去列舉每一個i和j,因此用雙重迴圈來解決,k表示第i個公司取的不取機器數,即1~i-1個公司取的機器數;f[i-1][k]表示前i-1個公司取k臺機器的最大值,a[i][j-k]表示第i個公司取剩餘的k臺機器的利益,那麼f[i-1][k]+a[i][j-k]表示的就是第i個公司不取k臺機器所得到的最大值,當然,k也是用迴圈來列舉的。

其中,k就是劃分的階段,來進行列舉不用的機器

emm.......

有點繞,畢竟我感覺資源分配的部落格是我一直相要寫的,卻一直不知道要怎麼表達,因此寫的有點繞,也只能在方程的基礎上解釋一下方程的意義了,那麼結合程式碼也許可以更好理解一些:

#include<bits/stdc++.h>
using namespace std;
int a[1000][1000],f[1000][1000]={},n,m;
int main()
{
	cin>>m>>n;
	for (int i=1;i<=n;i++)
	   for (int j=1;j<=m;j++)
	      cin>>a[i][j];
	for
(int i=1;i<=n;i++) for (int j=1;j<=m;j++) for (int k=0;k<=j;k++) f[i][j]=max(f[i][j],f[i-1][k]+a[i][j-k]); cout<<f[n][m]; return 0; }

2.修理馬棚

資源分配能夠理解,這道題就沒啥問題啦~~~

我們設f[i][j]為前i個馬棚前j個馬的最小值

因為這道題目在狀態轉移時需要用到衝突值,所以我們可以處理一個字首和,用t[i][j]表示第i到j頭馬的衝突值,處理方法如下:

1.用字首和one[i]和two[i]來記錄到i時白馬和黑馬的數量,用01區更方便

2.用二重迴圈列舉i和j,因為t[i][j]表示i到j的衝突值,所以相當於i到j的白馬*i到j的黑馬,也就可以表達為:t[i][j]=(one[j]-one[i-1])*(two[j]-two[j-1])

3.好了,衝突值處理好了,我們要將f陣列初始化了,因為狀態轉移方程f[i][j]=min(f[i][j],f[i-1][k]+t[k+1][j])中需要用到的前面狀態f[i-1][k]中,最小i-1位1,k可能比較大,所以我們至少要初始化f[1][i]=t[1][i],這是必須的,為了安全起見也可以寫一句f[i][1]=0.

4.同樣,不難得出狀態轉移方程f[i][j]=min(f[i][j],f[i-1][k]+t[k+1][j])

同樣可以列舉k,表示不同的牛的數量,第二個方程的含義是:前i-1個牛棚放k頭的最少衝突值加上第i個牛棚放剩下的牛的衝突值

ok~請看詳細程式碼:

#include<bits/stdc++.h>//f[i][j]表示i個馬棚j個馬的最小值 
using namespace std;
int t[1010][1010]={},f[1010][1010]={};
int n,k,a[10000]={},one[10000]={},two[10000]={};
int main()
{
	cin>>n>>k;//n:horse 
	for (int i=1;i<=n;i++)
	    cin>>a[i];
	memset(f,99,sizeof(f));
	for (int i=1;i<=n;i++)
	{
		if (a[i]==1) one[i]=one[i-1]+1;
		    else one[i]=one[i-1];
		if (a[i]==0) two[i]=two[i-1]+1;
		    else two[i]=two[i-1];
	}
	for (int i=1;i<n;i++)
	    for (int j=i+1;j<=n;j++)
	        t[i][j]=abs(one[j]-one[i-1])*abs(two[j]-two[i-1]);//預處理
	for (int i=1;i<=n;i++)
	    f[1][i]=t[1][i];
	for (int i=1;i<=n;i++)
	    f[i][1]=0; //初始化
	for (int i=2;i<=k;i++)
	    for (int j=1;j<=n;j++)
	    {
	    	for (int k=0;k<j;k++)
	    	    f[i][j]=min(f[i][j],f[i-1][k]+t[k+1][j]);
	    }//動態規劃
	cout<<f[k][n];
	return 0;
}
最後,關於動態規劃:

分清f陣列的含義,即前i和什麼前j個什麼的最優值;分清劃分階段的意義,即k的含義,在寫狀態轉移方程的時候就只要想前k個怎麼怎麼樣加上剩下的怎麼怎麼樣和原來最優值得最優值,就可以啦;適當的最字首和或預處理,更有利於程式的實現;

ok,資源分配下完啦,太可怕了!