poj1179 Polygon

来源:互联网 发布:全国所有省市县.json 编辑:程序博客网 时间:2024/05/01 15:40

        题意:一个多边形,顶点上有数字(有正有负),边上有加号或乘号。先选择一条边断开,使它成为链,然后每次选择一条边断开,按照符号和数字进行运算,求运算到只剩一个点时结果的最大值。

        思路:dp。处理第一次断开的位置很简单,直接先把它看成链,拷贝一份接在后面。然后因为有负数,所以dp的时候最大值最小值都要求出来,按区间长度递增递推dp即可。


#include <iostream>         #include <stdio.h>         #include <cmath>         #include <algorithm>         #include <iomanip>         #include <cstdlib>         #include <string>         #include <memory.h>         #include <vector>         #include <queue>         #include <stack>         #include <map>       #include <set>       #include <ctype.h>         #define INF 1000000010     #define ll long long     #define max3(a,b,c) max(a,max(b,c))     #define MAXN 1000using namespace std;     bool oper[105]; //0+ 1*int num[105];int dp[105][105];int dp2[105][105];int main(){int n;while(cin>>n){for(int i=0;i<=2*n;i++){for(int j=0;j<=2*n;j++){dp[i][j]=-INF;dp2[i][j]=INF;}}for(int i=0;i<n;i++){char c;cin>>c>>num[i];if(c=='t')oper[i]=0;else oper[i]=1;}oper[n]=oper[0];memcpy(oper+n,oper,n*sizeof(bool));memcpy(num+n,num,n*sizeof(int));for(int i=0;i<2*n;i++){dp2[i][i]=dp[i][i]=num[i];}for(int i=0;i<2*n-1;i++){if(oper[i+1]){dp2[i][i+1]=dp[i][i+1]=num[i]*num[i+1];}else{dp2[i][i+1]=dp[i][i+1]=num[i]+num[i+1];}}int ans=0;vector<int> ans2;for(int d=2;d<n;d++){for(int l=0;l+d<2*n-1;l++){for(int k=l;k<l+d;k++){if(oper[k+1]){dp[l][l+d]=max(dp[l][l+d],dp[l][k]*dp[k+1][l+d]);dp[l][l+d]=max(dp[l][l+d],dp2[l][k]*dp2[k+1][l+d]);dp2[l][l+d]=min(dp2[l][l+d],dp[l][k]*dp2[k+1][l+d]);dp2[l][l+d]=min(dp2[l][l+d],dp2[l][k]*dp[k+1][l+d]);}else{dp[l][l+d]=max(dp[l][l+d],dp[l][k]+dp[k+1][l+d]);dp2[l][l+d]=min(dp2[l][l+d],dp2[l][k]+dp2[k+1][l+d]);}}if(d==n-1){if(dp[l][l+d]==ans){ans=dp[l][l+d];ans2.push_back(l);}if(dp[l][l+d]>ans){ans=dp[l][l+d];ans2.clear();ans2.push_back(l);}}}}cout<<ans<<endl;for(int i=0;i<ans2.size();i++){cout<<ans2[i]+1;if(i!=ans2.size()-1)cout<<" ";}cout<<endl;}return 0;}



0 0