题目描述

多边形(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. git 让忽略.gitignore文件马上生效

    在.gitignore文件里面输入 *.zip 表示所有zip文件忽略更改 /bin 表示忽略整个根目录的bin文件夹 /src/aa.jar 表示忽略/src/aa.jar文件 设置完.gitign ...

  2. 模拟退火算法Python编程(3)整数规划问题

    1.整数规划问题 整数规划问题在工业.经济.国防.医疗等各行各业应用十分广泛,是指规划中的变量(全部或部分)限制为整数,属于离散优化问题(Discrete Optimization). 线性规划问题的 ...

  3. Java IO流知识总结

    Java IO的原理 I/O是Input和Output的缩写,用来处理设备之间的数据传输.如读/写文件,网络通讯等. Java程序中,对于数据的输入/输出操作以"流(stream)" ...

  4. 【参数校验】 自定义校验器 (实现ConstraintValidator)

    日常工作中写接口时,往往需要校验前端传来的枚举状态码,例如"1","2"等等, 这里使用java 303规范的参数校验框架封装一个自定义参数校验器: /** * ...

  5. 【docker-compose】docker-compose环境安装

    docker-compose: 是一个用于定义和运行多容器 Docker 的应用程序工具,可以帮助我们可以轻松.高效的管理容器 安装: 1.安装pip 工具-目的是为了下载docker-compose ...

  6. cmake VTK visual studio 2010

    使用cmake在configure之后,出现了以下错误,导致编译无法进行 The C compiler "cl" is not able to compile a simple t ...

  7. 在局域网内知道计算机的名字查找计算机的IP

    第一步 nbtstat -a 计算机名字 第二步 nbtstat -c 可以看到计算机地址

  8. 更好的滚动体验>better-scroll

    认识better-scroll better-scroll是一款重点用于解决移动端(已支持PC)各种滚动场景需求的插件,可使页面滚动效果更加流畅且富有弹性 better-scroll是用纯JavaSc ...

  9. [Qt] 基本概念

    QObject :所有 Qt 类的基类 QWidget类:包含所有组件的类 Widgets:组件,组成Qt界面的基本元素 window:界面,是不含有父组件的组件 Child Widgets:子组件, ...

  10. [刷题] 206 Reverse Linked List

    要求 反转一个链表 不得改变节点的值 示例 head->1->2->3->4->5->NULL NULL<-1<-2<-3<-4<-5 ...