[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 ...
随机推荐
- 【渲染引擎】Blender的2021年最佳渲染引擎(上)
Blender最终摆脱了"古怪的孩子"的装束,并穿上了更为严肃和受人尊敬的" 3D强者". 它已在业界获得广泛认可,许多工作室和艺术家正在将其纳入他们的产品线. ...
- oracle创建恢复编录(recovery catalog)
1.在要作为恢复编录的数据库创建用户 create user rman identified by oracle default tablespace system temporary TABLESP ...
- me21n增强BADI:ME_PROCESS_PO_CUST之process_account
当实施ME_PROCESS_PO_CUST这个badi来增强ME21N的时候,用了到方法process_account,既对ME21N的行项目的科目分配做增强.主要用到如下类: IF_PURCHASE ...
- 1.5V转3V电源芯片,1.5V转3V稳压芯片
1.5V干电池的供电电压一般是0.9V-1.6V左右,因为供电电压不稳,所以需要1.5V转3V的稳压电源芯片,当0.9V-1.6V输入电压时,输出电压能稳定3V输出,给模块供电,MCU供电,LED灯供 ...
- 【2020CSP-S模拟赛day5】总结
爆零自闭赛 写在前面 于2022.11.1 这一次题目质量很高(以至于什么都不会) 再一度体验了省选Orz.比赛大体情况,刨去std, wzc神仙230分,比剩下的加起来都高.zyz神仙60分. 其余 ...
- 百度文库Word下载器
最近我妈的文库VIP用完了,但还有很多资源要下载,于是我便在网上找下载工具. 总算找到个完美的!(虽然没界面) 既然没界面,那就自己写一个呗! 原作者 该程序的下载和写入部分由地球守卫者制作 原文链接 ...
- IDEA SSM+MAVEN+JWT 图书管理系统
压缩包内含有MAVEN,TOMCAT,需要手动对IDEA进行配置.同时也包含数据库文件. 项目搭载了swagger,可以方便地对接口进行测试 在开发的过程中我也进行了一些记录,可以参考https:// ...
- (003)每日SQL学习:普通视图和物化视图
关于这一点一直就是很懵懂的状态,今天特意网上查了一下资料,以下摘抄网上比较好的答案.以作记录. 普通视图和物化视图的区别答曰:普通视图和物化视图根本就不是一个东西,说区别都是硬拼到一起的,首先明白基本 ...
- FFmpeg libswscale源码分析1-API介绍
本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/14349382.html libswscale 是 FFmpeg 中完成图像尺寸缩放和像素 ...
- Java——时间和日期处理
Date Date date = new Date(); 获取时间 Date d = new Date(); // Date d2=new Date(System.currentTimeMillis( ...