题目描述

多边形(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. 1035 Password

    To prepare for PAT, the judge sometimes has to generate random passwords for the users. The problem ...

  2. php抽象类,接口,特性的比较

    php抽象类 抽象方法必须被子类继承实现,所以不能为私有,只能是受保护的或公有的; 抽象类子类的方法访问控制级别必须和抽象类相等或更宽松.例如,父类的抽象方法是受保护的,子类实现时则必须为受保护的或者 ...

  3. SSDT表函数Hook原理

    其实 SSDT Hook 的原理是很简单的,我们可以知道在 SSDT 这个数组中呢,保存了系统服务的地址,比如对于 Ring0 下的 NtQuerySystemInformation 这个系统服务的地 ...

  4. 缓冲区溢出分析第10课:Winamp缓冲区溢出研究

    前言 Winamp是一款非常经典的音乐播放软件,它于上世纪九十年代后期问世.与现在音乐播放软件行业百家争鸣的情况不同,当时可以说Winamp就是听音乐的唯一选择了,相信那个时代的电脑玩家是深有体会的. ...

  5. hdu4975 行列和构造矩阵(dp判断唯一性)

    题意:       和hdu4888一样,只不过是数据加强了,就是给你行列的和,让你构造一个矩阵,然后判断矩阵是否唯一. 思路:       构造矩阵很简单,跑一次最大流就行了,关键是判断矩阵的唯一性 ...

  6. hdu4038贪心(最快上升倍率,好题)

    题意:       给你n个数,然后有两种操作 1.给其中的一个数+1,2.在序列里面增加一个1,然后给你一个m,表示进行了m次操作,最后问你操作之后所有数乘积最大是多少? 思路:      徒弟给我 ...

  7. (二)SQL语句

    语法规则 不区分大小写,但是建议关键字大写,表名.列名小写 SELECT * FROM user; 支持多行编写sql语言(在SQLyog中可以用F12来快速格式化语句) # 查询cno=20201/ ...

  8. ThinkPHP5中出现unserialize()报错

    简述 unserialize(): Error at offset 533 of 1857 bytes 发现问题 dump一下出错的位置的变量,可以发现是缓存出了问题,改了名字的文件的路径对不上 解决 ...

  9. C++入门教程之二:变量

    C++入门教程之二:变量 变量,顾名思义,意思是变化的量.变量的定义是计算机语言中能储存计算结果或能表示值的抽象概念.一个基本的程序需要变量,因此变量是程序设计中的一大重点. 变量基本结构 var_t ...

  10. C++ primer plus读书笔记——第6章 分支语句和逻辑运算符

    第6章 分支语句和逻辑运算符 1. 逻辑运算符的优先级比关系运算符的优先级低. 2. &&的优先级高于||. 3. cctype中的函数P179. 4. switch(integer- ...