nyoj 61 傳紙條,nyoj 712 探尋寶藏 雙進程dp

題目鏈接:712:http://acm.nyist.net/JudgeOnline/problem.php?pid=712

題目大意是一個機器人從1.1出發,要到達m.n點,去的時候只能往右或往上走,回來的時候只能往上或往左走,但是一個點只能走一次,沿途每個點均有寶藏,問最多能拿回寶物的價值是多少。

此問題等價於從1.1出發兩個機器人,均要到達m.n點,設兩個機器人的速度是一定的,則每一個時刻兩個機器人均不能走到相同的格子內,(除了到達m.n的時候)。

若想去的兩個機器人不走到同一點,則只需要任意時刻,機器人1所在的行數不等於機器人2所在的行數。因爲速度相同,出發點相同,若某一時刻k時兩個機器人到達了同一行,則他們的列數也必然會相同,所以只需要不在同一行即可,

設f[k][i][j]爲第k步時1號機器人在i行2號機器人走到j行所收集的最大寶物價值,則f[k][i][j]=max(f[k-1][i-1][j],f[k-1][i][j-1],f[k-1][i][j],f[k-1][i-1][j-1])+a[i][k+2-i]+a[j][k+2-j];

如果設1號機器人走的是左邊的路線,2號機器人走的是右邊的路線,由於路線不想交,所以1號機器人第一步是往下的,而2號機器人是往右的,而到達終點前1號機器人不會達到第n列,同樣2號機器人不會到達第m行,然後i和j的取值範圍要考慮,必須使得兩個的行數均在(1,m)之間,列數均在(1,n)之間,而如果k+1<m時,行數均是小於m的,

我們同樣可以這樣考慮,由於機器人每前進一步,行數和列數有且僅有一個將增加1,所以我們可以考慮k的值代表行數和列數的和,則樣比較容易理解,由於到達終點的時候,兩條線路必須相交,所以我們可以不讓到達終點,即k<m+n;狀態轉移方程就變成了f[k][i][j]=max(f[k-1][i-1][j],f[k-1][i][j-1],f[k-1][i][j],f[k-1][i-1][j-1])+a[i][k-i]+a[j][k-j];(k>=3&&k<m+n);


參考代碼如下;

#include <iostream>
#include <cstring>
#define MAX_SIZE 51
using namespace std;
int f[2*MAX_SIZE+10][MAX_SIZE+10][MAX_SIZE+10];
int a[MAX_SIZE+10][MAX_SIZE+10];
int m,n;
int max(int a,int b)
{
	if(a>b)
		return a;
	return b;
}
void execute()
{
	if(m==1||n==1)
	{
		cout<<0<<endl;
		return ;
	}
	memset(f,0x80,sizeof(f));
	int k,i,j;
	f[2][1][1]=0;
	for(k=3;k<m+n;k++)
	{
		for(i=2;i<k&&i<=m;i++)
		{
			if(k-i>=n||k-i<1)
				continue;
			for(j=1;j<k-1&&j<=m-1;j++)
			{
				if(i==j)
					continue;
				if(k-j>n||k-j<=1)
					continue;
				f[k][i][j]=max(max(f[k-1][i-1][j],f[k-1][i-1][j-1]),max(f[k-1][i][j-1],f[k-1][i][j]));
				f[k][i][j]=f[k][i][j]+a[i][k-i]+a[j][k-j];
			}
		}
	}
	int ans=f[m+n-1][m][m-1]+a[m][n];
	cout<<ans<<endl;

}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		cin>>m>>n;
		for(int i=1;i<=m;i++)
			for(int j=1;j<=n;j++)
				cin>>a[i][j];
		execute();
	}
	return 0;
}



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