poj 1179 polygon 动规

题目链接:http://poj.org/problem?id=1179

翻译:“多边形”是一个关于有N个顶点的多边形的游戏。以图1为例:


这是一个N为4的多边形。每个顶点都代表一个整数,每条边都被一个操作符标记,这个操作符要么是“+”(加号)要么是“*”(乘法)。边由1到N进行标记。

游戏的第一边是去掉一条边。之后的步骤如下:

选择一条边E和它连接的两个顶点V1,V2;

然后用一个新的顶点来取代它们,这个顶点的值是V1和V2所代表的整数,进行了E所代表的运算得到的。

当边全部消除后,这个游戏结束,最终得分为最后那个顶点所代表的整数。

以图1的多边形为例,玩家首先去掉了第三边边,然后选择了第一条边,(进行运算后)再选择了第四条,最后第二条,最终得分为0.



写一个程序,要求在给定一个多边形的情况下,这个程序能算出可能得到的最高分,若先去掉某边能得到这个分数,把这条边标号输出。

状态方程:

               //all is the maxans
               dis=solve(maxans[i][(i+k)%n],maxans[(i+k+1)%n][(i+j)%n],oper[(i+k+1)%n]);
               if(dis>maxans[i][(i+j)%n])maxans[i][(i+j)%n]=dis;
               else if(dis<minans[i][(i+j)%n])minans[i][(i+j)%n]=dis;
               //all is the minans
               dis=solve(minans[i][(i+k)%n],minans[(i+k+1)%n][(i+j)%n],oper[(i+k+1)%n]);
               if(dis>maxans[i][(i+j)%n])maxans[i][(i+j)%n]=dis;
               else if(dis<minans[i][(i+j)%n])minans[i][(i+j)%n]=dis;

dis其实指的是区间内所能得到的最高分……

all is  the maxans和all is the minans与两种情况有关:

首先,如果是加法操作的话,当然直接选两段的最大值,相加就好。

但是,要考虑乘法,如果两段最大值分别为1,3,而最小值为-32和-34,显然两个最小值相乘的总得分会更大。

所以all is the maxans就是考虑两个点都是最大值的情况,all is the minans则是两个点都是最小值的情况。

每种情况算出的dis是i到i+k区间和i+k+1到i+j区间的得分之各,把它与当前i到i+j区间的得分比较,如果比它大,存在maxans里,否则,存在minans里。


由于枚举了删掉某一边的情况,所以要查找答案,看先删掉哪条边复分最高。

AC代码如下:

#include <iostream>
#include<cstdio>
#include<algorithm>
#define MAXN 55
using namespace std;
struct results{
	int n;
	int result;
};
char oper[MAXN];
int lines[MAXN];
int num[MAXN];
int maxans[MAXN][MAXN],minans[MAXN][MAXN];
int solve(int x, int y, char ope)
{
    if(ope=='t')return x+y;
    else return x*y;
}
int main()
{
    int n;//n numbers in total
	cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>oper[i]>>num[i];
        maxans[i][i]=num[i];
        minans[i][i]=num[i];
    }
    //initialization
    for(int i=1;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            maxans[j][(j+i)%n]=solve(maxans[j][j],maxans[(j+1)%n][(j+i)%n],oper[(j+1)%n]);
            minans[j][(j+i)%n]=maxans[j][(j+i)%n];
        }
    }
    //dp
    int dis;
    for(int j=1;j<n;j++)
    {
        for(int i=0;i<n;i++)
        {
            for(int k=0;k<j;k++)
            {
               //all is the maxans
               dis=solve(maxans[i][(i+k)%n],maxans[(i+k+1)%n][(i+j)%n],oper[(i+k+1)%n]);
               if(dis>maxans[i][(i+j)%n])maxans[i][(i+j)%n]=dis;
               else if(dis<minans[i][(i+j)%n])minans[i][(i+j)%n]=dis;
               //all is the minans
               dis=solve(minans[i][(i+k)%n],minans[(i+k+1)%n][(i+j)%n],oper[(i+k+1)%n]);
               if(dis>maxans[i][(i+j)%n])maxans[i][(i+j)%n]=dis;
               else if(dis<minans[i][(i+j)%n])minans[i][(i+j)%n]=dis;
            }
        }
    }
    //find ans;
    int ans=maxans[0][n-1];
	int cnt=0;
    for(int i=0;i<n;i++)
    {
       if(maxans[i][(i+n-1)%n]>ans)
        ans=maxans[i][(i+n-1)%n];
    }
    for(int i=0;i<n;i++)
    {
        if(maxans[i][(i+n-1)%n]==ans)
			lines[cnt++]=i;
    }
    sort(lines,lines+cnt);
   printf("%d\n",ans);
   //printf("%d*\n",cnt);
   for(int i=0;i<cnt-1;i++)
    printf("%d ",lines[i]+1);
   printf("%d\n",lines[cnt-1]+1);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值