POJ 1179 Polygon 矩陣鏈乘 記憶化搜尋
阿新 • • 發佈:2019-01-05
題目大意:
多邊形遊戲,有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; }