[IOI1998] Polygon (区间dp,和石子合并很相似)
题意:
给你一个多边形(可以看作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,和石子合并很相似)的更多相关文章
- IOI1998 Polygon [区间dp]
[IOI1998]Polygon 题意翻译 题目可能有些许修改,但大意一致 多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4.每个顶点用整数标记,每个边用符号+(加)或符号*(乘 ...
- nyoj737区间dp(石子合并)
石子合并(一) 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的 ...
- hihocoder1636 Pangu and Stones(区间DP(石子合并变形))
题目链接:http://hihocoder.com/problemset/problem/1636 题目大意:有n堆石头,每次只能合并l~r堆,每次合并的花费是要合并的石子的重量,问你合并n堆石子的最 ...
- 区间dp之 "石子合并"系列(未完结)
A. 石子合并<1> 内存限制:128 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统评测 方式:文本比较 题目描述 有N堆石子排成一排(n<=100),现要将石 ...
- 整数划分——区间dp(石子合并)
这不是将一个数以一来划分,而是把一个整数以位来划分 题目描述 如何把一个正整数N(N长度<20)划分为M(M>1)个部分,使这M个部分的乘积最大.N.M从键盘输入,输出最大值及一种划分方式 ...
- 区间DP经典 石子合并
题目链接 题意:环形的一群石子,每次可以选择相邻的两堆合并,分数为新得到的一堆石子,求将这片石子合并成一堆的最大和最小分数 输入:第一行一个正整数n,其后n个数代表每堆石子的个数 分析:第一次写的时候 ...
- 【IOI1998】Polygon 区间DP
题意翻译 题目可能有些许修改,但大意一致 多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4.每个顶点用整数标记,每个边用符号+(加)或符号*(乘积)标记. 第一步,删除其中一条边 ...
- POJ 1179 - Polygon - [区间DP]
题目链接:http://poj.org/problem?id=1179 Time Limit: 1000MS Memory Limit: 10000K Description Polygon is a ...
- 2017北京网络赛 J Pangu and Stones 区间DP(石子归并)
#1636 : Pangu and Stones 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 In Chinese mythology, Pangu is the fi ...
随机推荐
- 【Java基础】Java11 新特性
Java11 新特性 新增字符串处理方法 新增方法: 判断字符串是否为空白 " ".isBlank(); // true 去除首尾空白 " Javastack " ...
- 牛客网NC15二叉树的层次遍历
题目 给定一个二叉树,返回该二叉树层序遍历的结果,(从左到右,一层一层地遍历) 例如: 给定的二叉树是{3,9,20,#,#,15,7}, 该二叉树层序遍历的结果是 [ [3], [9,20], [1 ...
- Nginx基础知识学习(安装/进程模型/事件处理机制/详细配置/定时切割日志)
一.Linux下Nginx的安装 1.去官网 http://nginx.org/download/下载对应的Nginx安装包,推荐使用稳定版本. 2.上传Nginx到Linux服务器. 3.安装依赖环 ...
- ECC 6 debuging中create points
2013-12-07 今天无意中,发现,在ECC6中debug的时候,创建动态断点,对于command中的delete from语句居然无效,唉 虽然设置了DELETE 和DELETE FROM两个动 ...
- nodejs中使用worker_threads来创建新的线程
目录 简介 worker_threads isMainThread MessageChannel parentPort和MessagePort markAsUntransferable SHARE_E ...
- 基于 WebRTC 实现自定义编码分辨率发送
2020年如果问什么技术领域最火?毫无疑问:音视频.2020年远程办公和在线教育的强势发展,都离不开音视频的身影,视频会议.在线教学.娱乐直播等都是音视频的典型应用场景. 更加丰富的使用场景更需要我们 ...
- 《进击吧!Blazor!》第一章 1.初识 Blazor
作者介绍 陈超超 Ant Design Blazor 项目贡献者 拥有十多年从业经验,长期基于.Net技术栈进行架构与开发产品的工作,Ant Design Blazor 项目贡献者,现就职于正泰集团 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(89)-国际化,本地化,多语言应用
开篇 早年写过一篇多语言的应用 : 本地化(多语言) 讲述了如何创建多语言的资源文件,并利用资源文件来获得页面和请求的语言属性 本次补充这篇文章,的原因是在实际项目中,有多种需要多语言的情况 ...
- 我教你如何解决 Docker 下载 mcr.microsoft.com 镜像慢的办法
我教你如何解决 Docker 下载 mcr.microsoft.com 镜像慢的办法 一.介绍 最近,我在写有关使用 Jenkins 搭建企业级持续集成环境的文章,准备了四台服务器,企业级别嘛,一台就 ...
- jemeter断言和性能分析
一.添加断言 1.原因:检查是否有该结果,一般一个请求过去除了400和500的只要通过的都会代表请求成功,比如登录页面及时填写了错误密码,虽然会返回密码错误,但这个请求还是成功的,所以我们要添加断言, ...