题意:

给你一个多边形(可以看作n个顶点,n-1条边的图),每一条边上有一个符号(+号或者*号),这个多边形有n个顶点,每一个顶点有一个值

最初你可以把一条边删除掉,这个时候这就是一个n个顶点,n-2条边的图

如果顶点i和j之间有边,那么你可以把i点和j点合并成一个点,把这个点替换掉i、j两个点,这个新点的值是i+j 或者 i*j (这个是要看连接i和j两点的边上的符号)

经过若干次操作之后剩下一个点,这个点的值最大是多少

题解:

这道题目和石子合并题目很相似,这里先说一下石子合并

题目:

有N堆石子围成一个圆,现要将石子有序的合并成一堆,规定如下:每次只能移动相邻的2堆石子合并,合并花费为新合成的一堆石子的数量。求将这N堆石子合并成一堆的总花费最小(或最大)。

我们来分析一下,给你 4 堆石子:4,5,6,7,按照下图所示合并

这种合并方式的花费为:4+5+9+6+15+7=46

这种合并也就是4->5->6->7按照这个方向进行

那我们先合并前3堆石子:4+5+9+6

这个花费就是:第一堆和第二堆合并的花费+第一堆和第二堆合并之后的数量+第三堆的数量

那我们先合并前4堆石子:4+5+9+6+15+7

这个花费就是:第一堆和第二堆和第三堆合并的花费(也就是4+5+9+6)+第一堆和第二堆和第三堆合并之后的数量+第四堆的数量

大问题分解成了小问题,而且大问题包含了小问题的解,大问题和小问题同质同解。完完全全满足dp的性质。

剩下的就是从中找到最优解,因为当前是从1->2->3->4的顺序去合并的,还有(1->2)->(3->4)或者1->(2->3->4)的顺序,原理一样,这里面因为第二第三部分是固定的,所以只需要得到小问题的最优解,就可以求得大问题的最优解了。这一点我们可以把原序列复制一份追加到原序列尾部,然后使用区间dp枚举就可以了

这里给出石子合并问题求最大花费的代码:dp[i][j]表示:从石子i合并到石子j所能得到的最大花费

 1 #include<bits/stdc++.h>
2 using namespace std;
3 const int maxn=450;//区间长度为2*n
4 int dp[maxn][maxn];
5 int sum[maxn];//前缀和数组
6 int a[maxn];//每堆石子的个数
7 int main()
8 {
9 int n,x;
10 sum[0]=0;
11 while(scanf("%d",&n)!=EOF){
12 memset(dp,0,sizeof(dp));
13 memset(sum,0,sizeof(sum));
14 for(int i=1;i<=n;i++){
15 scanf("%d",&a[i]);
16 sum[i]=sum[i-1]+a[i];//预处理
17 dp[i][i]=0;
18 }
19
20 int in=1;//首尾相连之后
21 for(int i=n+1;i<=2*n;i++)
22 sum[i]+=(sum[i-1]+a[in++]);
23
24 for(int len=2;len<=n;len++)//枚举区间长度
25 {
26 for(int i=1;i<=2*n;i++)//枚举区间起点
27 {
28 int j=i+len-1;//区间终点
29 if(j>n*2) break;//越界结束
30 for(int k=i;k<j;k++)//枚举分割点,构造状态转移方程
31 {
32 dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+(sum[j]-sum[i-1]));
33 }
34 }
35 }
36 int MAX=-1;
37 for(int i=1;i<=n;i++)//枚举环状序列的起点,长度为n
38 MAX=max(dp[i][i+n-1],MAX);//求最大值
39 printf("%d\n",MAX);
40 }
41 return 0;
42 }

回归原题,这个题目如果所有边的符号都是+号,那就和石子合并一样了

这里多了一个*号,那么两个很小的负数相乘也可以得到一个很大的值,这样的话,我们可以开一个三维dp,dp[i][j][k]:如果k==1,那就保存的是dp[i][j]的max

如果k==0,那就保存dp[i][j]的最小值

其他和正常区间dp一样

代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define mem(a) memset(a,0,sizeof(a))
typedef long long ll;
const int maxn=55;
const int INF=0x3f3f3f3f;
const double blo=(1.0+sqrt(5.0))/2.0;
const double eps=1e-8;
struct shudui
{
int a,b;
}que[maxn];
int dp[maxn][maxn][2],num[maxn],str[maxn];
int main()
{
int n;
while(~scanf("%d",&n))
{
char s[maxn];
for(int i=1;i<=2*n;++i)
{
if(i%2)
{
scanf("%s",s);
str[i/2]=s[0];
}
else
{
scanf("%d",&num[(i-1)/2]);
}
}
str[n]=str[0];
for(int i=0;i<n;++i)
{
for(int j=0;j<n;++j)
{
if(i==j)
dp[i][j][0]=dp[i][j][1]=num[i];
else
{
dp[i][j][0]=INF;
dp[i][j][1]=-INF;
}
}
}
for(int len=1;len<n;++len)
{
for(int i=0;i<n;++i)
{
//int j=(i+len)%n;
int j=(i+len);
for(int k=i;k<j;++k)
{
if(str[(k+1)%n]=='t')
{
dp[i][j%n][1]=max(dp[i][j%n][1],dp[i][k%n][1]+dp[(k+1)%n][j%n][1]);
dp[i][j%n][0]=min(dp[i][j%n][0],dp[i][k%n][0]+dp[(k+1)%n][j%n][0]);
}
else
{
dp[i][j%n][1]=max(dp[i][j%n][1],dp[i][k%n][1]*dp[(k+1)%n][j%n][1]);
dp[i][j%n][1]=max(dp[i][j%n][1],dp[i][k%n][0]*dp[(k+1)%n][j%n][0]);
dp[i][j%n][0]=min(dp[i][j%n][0],dp[i][k%n][0]*dp[(k+1)%n][j%n][1]);
dp[i][j%n][0]=min(dp[i][j%n][0],dp[i][k%n][1]*dp[(k+1)%n][j%n][0]);
dp[i][j%n][0]=min(dp[i][j%n][0],dp[i][k%n][0]*dp[(k+1)%n][j%n][0]);
}
}
}
}
//printf("%d %d %d %d\n",dp[1][2][1],dp[2][1][1],dp[2][3][1],dp[3][2][1]);
int maxx=-INF,index=0;
for(int i=0;i<n;++i)
{
maxx=max(maxx,dp[i][(i+n-1)%n][1]);
}
for(int i=0;i<n;++i)
{
if(dp[i][(i+n-1)%n][1]==maxx)
{
//printf("%d %d\n",i,(i+n-1)%n);
que[index++].a=i+1;
//que[index++].b=max((i+n-1)%n,i)+1;
//que[index++].a=i+1;
}
}
printf("%d\n",maxx);
for(int i=0;i<index;++i)
{
//printf("%d %d\n",que[i].a,que[i].b);
if(i==index-1)
printf("%d\n",que[i].a);
else printf("%d ",que[i].a);
}
}
return 0;
}

[IOI1998] Polygon (区间dp,和石子合并很相似)的更多相关文章

  1. IOI1998 Polygon [区间dp]

    [IOI1998]Polygon 题意翻译 题目可能有些许修改,但大意一致 多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4.每个顶点用整数标记,每个边用符号+(加)或符号*(乘 ...

  2. nyoj737区间dp(石子合并)

    石子合并(一) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述     有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的 ...

  3. hihocoder1636 Pangu and Stones(区间DP(石子合并变形))

    题目链接:http://hihocoder.com/problemset/problem/1636 题目大意:有n堆石头,每次只能合并l~r堆,每次合并的花费是要合并的石子的重量,问你合并n堆石子的最 ...

  4. 区间dp之 "石子合并"系列(未完结)

    A. 石子合并<1> 内存限制:128 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统评测 方式:文本比较   题目描述 有N堆石子排成一排(n<=100),现要将石 ...

  5. 整数划分——区间dp(石子合并)

    这不是将一个数以一来划分,而是把一个整数以位来划分 题目描述 如何把一个正整数N(N长度<20)划分为M(M>1)个部分,使这M个部分的乘积最大.N.M从键盘输入,输出最大值及一种划分方式 ...

  6. 区间DP经典 石子合并

    题目链接 题意:环形的一群石子,每次可以选择相邻的两堆合并,分数为新得到的一堆石子,求将这片石子合并成一堆的最大和最小分数 输入:第一行一个正整数n,其后n个数代表每堆石子的个数 分析:第一次写的时候 ...

  7. 【IOI1998】Polygon 区间DP

    题意翻译 题目可能有些许修改,但大意一致 多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4.每个顶点用整数标记,每个边用符号+(加)或符号*(乘积)标记. 第一步,删除其中一条边 ...

  8. POJ 1179 - Polygon - [区间DP]

    题目链接:http://poj.org/problem?id=1179 Time Limit: 1000MS Memory Limit: 10000K Description Polygon is a ...

  9. 2017北京网络赛 J Pangu and Stones 区间DP(石子归并)

    #1636 : Pangu and Stones 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 In Chinese mythology, Pangu is the fi ...

随机推荐

  1. 【Spring】Spring IOC

    Spring IOC IOC 的常用注解 小节源码 之前的 XML 配置: <bean id="accountService" class="cn.parzulpa ...

  2. 【Flutter】可滚动组件之SingleChildScrollView

    前言 SingleChildScrollView类似于Android中的ScrollView,它只能接收一个子组件. 接口描述 const SingleChildScrollView({ Key ke ...

  3. 剑指 Offer 16. 数值的整数次方

    实现函数double Power(double base, int exponent),求base的exponent次方.不得使用库函数,同时不需要考虑大数问题. 来源:力扣(LeetCode) 链接 ...

  4. linux线程数限制与zabbix监控

    Linux最大线程数限制及当前线程数查询 最大线程数计算方式: n = total_memory/128k; Linux用户线程数限制而导致的程序异常为 java.lang.OutOfMemoryEr ...

  5. xtrabackup_binlog_info

    文件保存了备份结束时刻binlog的名称和位置

  6. ctfshow—web—web签到题

    打开靶机,发现只有一句话 查看源码 发现一段字符串,猜是base64加密 拿到flag

  7. 【葵花宝典】kolla部署OpenStack-AllinOne

    1.关闭防火墙以及内核安全机制 systemctl stop firewalld systemctl disable firewalld ##永久性关闭 setenforce 0 sed -i 's/ ...

  8. Table controls and tabstrip controls

    本文转载自http://www.cnblogs.com/clsoho/archive/2010/01/21/1653268.html ONTROLS Syntax Forms Declaration ...

  9. Python爬虫要学什么?写给小白的Python爬虫必备技能

    Python在爬虫方面用得比较多,所以你如果能掌握以下内容,找工作的时候就会顺利很多: 1.爬虫,不是抓取到数据就完事了,如果有数据抽取.清洗.消重等方面经验,也是加分项; 2.大部分的公司都要求爬虫 ...

  10. JVM(二)类加载的时机及其过程

    类从被加载到虚拟机内存中开始,到卸载出内存为止,它的的整个生命周期包括: 加载(Loading),验证(Verification),准备(Preparation),解析(Resolution),初始化 ...