题目描述

多边形(Polygon)游戏是单人玩的游戏,开始的时候给定一个由N个顶点构成的多边形(图1所示的例子中,N=4),每个顶点被赋予一个整数值,而每条边则被赋予一个符号:+(加法运算)或者*(乘法运算),所有边依次用整数1到N标识。

图1:一个多边形的图形表示 首次移动(first move),允许将某条边删除; 接下来的每次顺序移动(subsequentmoves),包括下面步骤:

1、选出一条边E,以及由E联接的顶点V1和V2;

2、用一个新的顶点,取代边E及其所联接的两个顶点V1和V2。新顶点要赋予新的值,这个值是对V1和V2,做由E所指定的运算,所得到的结果。

所有边都被删除后,只剩下一个顶点,游戏结束。游戏的得分就是该顶点的数值。 下面是一个游戏实例: 考虑图1中的多边形。

玩家第一步删除第3条边。结果如图2所示。  图2 删除第3条边

之后,玩家删除第1条边  图3 删除第1条边

然后删除第4条边,  图4 删除第4条边

最后删除第2条边。得分是0.  图5 删除第2条边 任务: 编写一个程序,对于任意给定的多边形,计算可能的最高得分,并且列举出所有的可以导致最高得分的被首次移动的边。

输入格式

文件POLYGON.IN给出的是,由N个顶点构成的多边形。文件包括2行: 第一行记录的是数值N(n<=50); 第二行包含所有边(1,…,N)分别被赋予的符号,以及嵌入到两条边之间的顶点的数值(第一个整数值对应于与1号、2号边同时相连的顶点;第二个整数对应于与2号、3号边同时相连的顶点;…;等等。最后一个数值对应于与N号、1号边同时相连的顶点),符号和数值之间由一个空格分隔。边的符号有2种:字母t(对应于+),字母x(对应于*)。

输出格式

在文件POLYGON.OUT的第一行,你的程序必须输出在输入文件指定条件下可能得到的最高得分。 有些边如果在首次移动中被删除,可以导致最高得分。在输出文件的第二行,要求列举出所有这样的边,而且按照升序输出,其间用一个空格分开。

样例

样例输入

4
t -7 t 4 x 2 x 5

样例输出

33
1 2

数据范围与提示

样例输入对应于图1所示的多边形。第二行的第一个字符是1号边的符号。

此题类似石子合并,将环状多边形转换成链,由n转入2*n+1个字符。

总数量不能变,所以一点一点向后推移;

先进行一个循环,决定去掉那条边,再加n,向后推移;

f[i][j],表示从i到j的最优解;

每一个点必定是由两个点组成,so,在i,j区间枚举分割点,注意分割点不能等于j;

因为这题中,数字有正有负,必然要考虑负负得正的情况

例如,-1000*-1000=1000000 100*100=10000 而1000000>10000,但-1000却小于100;

所以每一次合并必然要考虑最小值和最大值;

如果下一次合并时,符号是‘+’,那就直接将最大值和最小值相加;

若是‘*’,那就将大*大,大*小,小*大,小*小四种比较一下,寻找最大值和最小值;

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int n,shu[150],f[150][150][3],sum[150][150],ff[150]={0},ma,mb,a,b,c,d;
char fu[150];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>fu[i]>>shu[i];//先输入符号,在输入数字
}
for(int i=n+1;i<=2*n;i++)
{
shu[i]=shu[i-n];
fu[i]=fu[i-n];
}
for(int i=1;i<=n;i++)
{
for(int o=1;o<=2*n;o++)
{
for(int p=1;p<=2*n;p++)
{
f[o][p][1]=-9999999;//求大值,初始化最小
f[o][p][2]=9999999;//求小值,初始化最大
}
}
for(int q=1;q<=2*n;q++)//初始化区间dp
{
f[q][q][1]=shu[q];
f[q][q][2]=shu[q];
if(fu[q+1]=='t')
{
f[q][q+1][1]=shu[q]+shu[q+1];
f[q][q+1][2]=shu[q]+shu[q+1];
}
if(fu[q+1]=='x')
{
f[q][q+1][1]=shu[q]*shu[q+1];
f[q][q+1][2]=shu[q]*shu[q+1];
}
}
for(int l=2;l<=n;l++)
{
for(int j=i;j<=i+n-l;j++)
{
int k=j+l-1;
for(int x=j;x<k;x++)//一定要小于k,因为后面有x+1;
{
if(fu[x+1]=='t'&&f[j][k][1]<f[j][x][1]+f[x+1][k][1])f[j][k][1]=f[j][x][1]+f[x+1][k][1];
if(fu[x+1]=='t'&&f[j][k][2]>f[j][x][2]+f[x+1][k][2])f[j][k][2]=f[j][x][2]+f[x+1][k][2];
if(fu[x+1]=='x')
{
a=f[j][x][1]*f[x+1][k][1];
b=f[j][x][2]*f[x+1][k][1];
c=f[j][x][1]*f[x+1][k][2];
d=f[j][x][2]*f[x+1][k][2];
f[j][k][1]=max(max(max(a,b),max(c,d)),f[j][k][1]);
f[j][k][2]=min(min(min(a,b),min(c,d)),f[j][k][2]);
}
}
}
}
ff[i]=f[i][i+n-1][1];
}
ma=-1000000;
for(int i=1;i<=n;i++)//寻找最大值
{
if(ma<ff[i])
{
ma=ff[i];
mb=i;
}
}
cout<<ma<<endl;
for(int i=1;i<=n;i++)
{
if(ff[i]==ma)
{
cout<<i<<" ";//输出可以断第几个
}
}
}
/*
4 120
x 2 x 3 x 4 x 5 1 2 3 4 6 10000
x -10 x -10 x -10 t 10 t 10 t 10 6 7 300000
x -10 x -10 x -10 x -10 t 10 t 10 t 10 5
以上是三组测试数据*/

以上是个人见解,,如有不妥请评论区发表意见

以下是改进后的代码

#include<bits/stdc++.h>
using namespace std;
int n,num[105],dp1[105][105],dp2[105][105],maxn[55],maxx;
char fu[105];
int main()
{
memset(dp1,0x8f,sizeof(dp1));
memset(dp2,0x3f,sizeof(dp2));
cin>>n;
for(int i=1;i<=n;i++){
cin>>fu[i]>>num[i];
fu[n+i]=fu[i];
num[n+i]=dp1[i][i]=dp1[n+i][n+i]=dp2[i][i]=dp2[n+i][n+i]=num[i];
}
for(int o=1;o<=n;o++){
for(int l=2;l<=n;l++){
for(int i=o;i<=o+n-l;i++){
int j=i+l-1;
for(int k=i+1;k<=j;k++){
int a,b,c,d;
if(fu[k]=='t'){
a=dp1[i][k-1]+dp1[k][j];
b=dp2[i][k-1]+dp2[k][j];
dp1[i][j]=max(dp1[i][j],a);
dp2[i][j]=min(dp2[i][j],b);
}
if(fu[k]=='x'){
a=dp1[i][k-1]*dp1[k][j];
b=dp1[i][k-1]*dp2[k][j];
c=dp2[i][k-1]*dp2[k][j];
d=dp2[i][k-1]*dp1[k][j];
dp1[i][j]=max(dp1[i][j],max(a,max(b,max(c,d))));
dp2[i][j]=min(dp2[i][j],min(a,min(b,min(c,d))));
}
}
}
}
maxn[o]=dp1[o][o+n-1];
maxx=max(maxx,dp1[o][o+n-1]);
}
cout<<maxx<<endl;
for(int i=1;i<=n;i++){
if(maxn[i]==maxx)
cout<<i<<" ";
}
}

多边形游戏——区间dp的更多相关文章

  1. 多边形游戏 /// 区间DP oj1903

    题目大意: ... Input 输入的第一行是单独一个整数n( 3 ≤ n ≤ 18 ),表示多边形的顶点数(同时也是边数). 接下来第n行,每行包含一个运算符("+"或" ...

  2. Vijos 1565 多边形 【区间DP】

    描述 zgx给了你一个n边的多边形,这个多边形每个顶点赋予一个值,每条边都被标上运算符号+或*,对于这个多边形有一个游戏,游戏的步骤如下:(1)第一步,删掉一条边:(2)接下来n-1步,每步对剩下的边 ...

  3. P1005 矩阵取数游戏[区间dp]

    题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的\(m*n\)的矩阵,矩阵中的每个元素\(a_{i,j}\)均为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n个.经过m次后 ...

  4. 圆桌游戏(区间DP)

    2.圆桌游戏 (game.cpp/c/pas) [问题描述] 有一种圆桌游戏是这样进行的:n个人围着圆桌坐成一圈,按顺时针顺序依次标号为1号至n号.对1<=i<=n的i来说,i号的左边是i ...

  5. BZOJ 2121: 字符串游戏 区间DP + 思维

    Description BX正在进行一个字符串游戏,他手上有一个字符串L,以及其他一些字符串的集合S,然后他可以进行以下操作:对 于一个在集合S中的字符串p,如果p在L中出现,BX就可以选择是否将其删 ...

  6. 洛谷 P1043 数字游戏 区间DP

    题目描述 丁丁最近沉迷于一个数字游戏之中.这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易.游戏是这样的,在你面前有一圈整数(一共n个),你要按顺序将其分 ...

  7. qscoj 喵哈哈村的打印机游戏 区间dp

    点这里去看题 区间dp ,dp[l][r][d]代表从l到r的区间底色为d,具体看代码 第一次见到区间dp...两个小时对着敲了五遍终于自己敲懂了一遍ac #include<bits/stdc+ ...

  8. 多边形游戏(DP)

    Description 多边形游戏是一个单人玩的游戏,开始时有一个由n个顶点构成的多边形.每个顶点被赋予一个整数值,每条边被赋予一个运算符 "+" 或 "*". ...

  9. 【bzoj2121】字符串游戏 区间dp

    题目描述 给你一个字符串L和一个字符串集合S,如果S的某个子串在S集合中,那么可以将其删去,剩余的部分拼到一起成为新的L串.问:最后剩下的串长度的最小值. 输入 输入的第一行包含一个字符串,表示L. ...

随机推荐

  1. 『政善治』Postman工具 — 1、Postman介绍与安装

    目录 一.Postman介绍 二.Postman下载与安装 1.Postman下载 2.Postman安装 3.为什么要注册Postman账号 一.Postman介绍 Postman是一款非常流行的H ...

  2. wordpress 自定义路由及展示页

    wordpress 自定义路由及展示页 注册domain/test这个路由 wordpress 有重写url的方法,叫 add_rewrite_rule().在function.php中加入如下代码段 ...

  3. php异常及错误信息捕获并记录日志实现方法全解析

    php异常处理 什么是异常? PHP 5 提供了一种新的面向对象的错误处理方法.异常处理用于在指定的错误(异常)情况发生时改变脚本的正常流程.这种情况称为异常. 当异常被触发时,通常会发生: 当前代码 ...

  4. hdu2435最大流最小割

    2435  There is a war 题意:       给你一个有向图,其中可以有一条边是无敌的,这条边可以是图中的边,也可以是自己任意加上去的图中没有的边,这条无敌的边不可以摧毁,让1和n无法 ...

  5. POJ2536 二分图匹配

    题意:      有n只老鼠,m个洞,每个洞最多可以藏一只老鼠,每个老鼠的移动速度都是v,给你他们的当前坐标,和洞的坐标,突然老鹰来了,他们必须在s秒内跑到一个洞藏起来,问你最少有多少只老鼠被抓走了. ...

  6. hdu4993(水题)

    题意:       x * a + y * b = c xyab都是正整数,给你a,b,c问有多少对xy组合满足等式. 思路:       水题,直接枚举其中一个,然后看求出的y是不是正整数就行了,第 ...

  7. POJ2044 深搜+剪枝(云彩下雨)

    题意:        有一个城镇,是4*4的大小的,然后你控制一块云彩,2*2的,你每天可以有9种走的方法,上下左右,或者不动,走的时候可以走1或者2步,云彩所在的地方肯定会下雨,然后给你做多365天 ...

  8. 使用 WinAFL 图片解析软件进行模糊测试 - FreeImage 图片解析库

    看雪链接:https://bbs.pediy.com/thread-255162.htm

  9. java之泛型的使用

    在java中,普通的类和方法只能用具体的类型,这对代码的限制很大,代码的可重用性大大降低. 那么如何才能让同一个类和方法使用不同类型的对象呢?在接触泛型之前我们可能会想到通过类型转换的方法来实现. p ...

  10. Outlook关闭时最小化

    一:背景环境: 当使用Outlook的时候,不小心点关闭,会不能及时发现接收的新邮件. 二:解决方法: 利用KeepOutlookRunning.dll插件,可以实现,点击关闭时,outlook没有实 ...