1. 程式人生 > >POJ 1179 Polygon 矩陣鏈乘 記憶化搜尋

POJ 1179 Polygon 矩陣鏈乘 記憶化搜尋

題目大意:

多邊形遊戲,有N個頂點的多邊形,3 <= N <= 50 ,多邊形有N條邊,每個頂點中有一個數字(可正可負),每條邊上或者是“+”號,或者是“*”號。邊從1到N編號,首先選擇一條邊移去,然後進行如下操作:

1 選擇一條邊E和邊E連線著的兩個頂點V1,V2。

2 用一個新的頂點代替邊E和V1、V2,新頂點的值為V1、V2中的值進行邊上代表的操作得來(相加或相乘)

當最後只剩一個頂點,沒有邊時,遊戲結束。現在的任務是程式設計求出最後的頂點能獲得的最大值,以及輸出取該最大值時,第一步需移去的邊,如果有多條符合條件的邊,按編號從小到大輸出

題目分析:

求獲得的最大值,是個dp的過程,dp[i][j]=max(dp[i][k](opt操作)dp[k+1][j])表示從i到j能獲得最大值,也就是合併k和k+1

考慮到dp[i][j]是一段區間的最大值,每次dp會重複利用到裡面的值,所以用記憶化搜尋。

其中的最大值,可能由最小值得到,所以要同時儲存最小值。

其中每次dfs(i,i+n-1),也就是斷開i-1和i,dp一個以i開頭的長度為N的鏈。

總結一下:這道題是一個區間dp的題目,並且是個環,所以在dp的時候要注意,處理的時候對於>n的對n進行取餘。

核心程式碼

for(int i=l;i<r;i++)
 {
  q1=dfs(l,i),q2=dfs(i+1,r);
  Max=max(Max,);
  Min=min(Min,); 
 } 
 return dp[l%n][r%n]=make_pair(Max ,Min);

如下標準程式碼:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#define N 310 
#define LL long long 
const long long INF = (LL)1<<59; 
inline LL getmax(LL a,LL b)
{
    return a<b?b:a;   
} 
inline LL getmin(LL a,LL b)
{
    return a<b?a:b;    
}
using namespace std;
int n,m;
pair<LL,LL> dp[N][N];
long long  num[N],ans=0;
char G,opt[N];
vector<int>VV;
inline pair<LL,LL> dfs(int l,int r)
{
    if(l==r)
        return make_pair(num[l%n],num[r%n]);
    if(dp[l%n][r%n].first!=INF)
        return dp[l%n][r%n];
    LL Max=-INF,Min=INF,res;
    pair<LL,LL> p1,p2;
    for(int i=l;i<r;i++)
    {
        res=0;
        p1=dfs(l,i),p2=dfs(i+1,r);   
        if(opt[(i+1)%n]=='t')
        {
            res=p1.first+p2.first;
            Max=getmax(Max,res); 
            res=p1.second+p2.second;
            Min=getmin(Min,res);   
        }
        else 
        {
            res=p1.first*p2.first;
            Max=getmax(Max,res);
            res=p1.second*p2.second;
            Max=getmax(res,Max);
            res=p1.first*p2.second;
            Max=getmax(res,Max);
            res=p1.second*p2.first;
            Max=getmax(res,Max);
            res=p1.first*p2.second;
            Min=getmin(Min,res);
            res=p2.first*p1.second;
            Min=getmin(Min,res);
            res=p1.second*p2.second;
            Min=getmin(Min,res);
            res=p1.first*p2.first;
            Min=getmin(Min,res);
        }
    }   
    return dp[l%n][r%n]=make_pair(Max,Min);  
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++)
           for(int j=0;j<n;j++)
           dp[i][j].first=dp[i][j].second=INF;
        for(int i=0;i<n;i++)
        cin>>opt[i]>>num[i];
        LL ans=-INF;
        for(int i=0;i<n;i++)
        {
            LL tem=dfs(i,i+n-1).first;
            if(tem>ans)
            {
                ans=tem;
                VV.clear();
                VV.push_back(i+1);    
            }       
            else if(tem==ans) 
            {
                VV.push_back(i+1);
            }
        }
        printf("%lld\n",ans);
        for(int i=0;i<(int)VV.size();i++)
        {
            printf("%d%s",VV[i],i==(VV.size()-1)?"\n":" ");    
        } 
    }
   	 while(1);
    return 0;
}