[dp]HDOJ4960 Another OCD Patient
题意: 给一个n, 第二行给n堆的价值v[i], 第三行给a[i]. a[i]表示把i堆合在一起需要的花费.
求把n堆变成类似回文的 需要的最小花费.
思路:
①记忆化搜索 比较好理解...
dp[l][r] 记录l到r的最小花费
枚举对称轴 维护每次l到r之间对称
dp[l][r]=min(dp[l][r], a[cur-l]+a[r-i]+dfs(cur+1, i-1));
l左边和r右边的合并
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cctype>
#include <cmath>
#include <string>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
#include <queue>
#include <stack>
#include <vector>
#include <deque>
#include <set>
#include <map>
typedef long long LL;
typedef long double LD;
#define pi acos(-1.0)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
typedef pair<int, int> PI;
typedef pair<int, PI> PP;
#ifdef _WIN32
#define LLD "%I64d"
#else
#define LLD "%lld"
#endif
//#pragma comment(linker, "/STACK:1024000000,1024000000")
//LL quick(LL a, LL b){LL ans=1;while(b){if(b & 1)ans*=a;a=a*a;b>>=1;}return ans;}
//inline int read(){char ch=' ';int ans=0;while(ch<'0' || ch>'9')ch=getchar();while(ch<='9' && ch>='0'){ans=ans*10+ch-'0';ch=getchar();}return ans;}
inline void print(LL x){printf(LLD, x);puts("");}
//inline void read(double &x){char c = getchar();while(c < '0') c = getchar();x = c - '0'; c = getchar();while(c >= '0'){x = x * 10 + (c - '0'); c = getchar();}} int a[];
LL num[];
int cost[];
int dp[][];
int dfs(int l, int r)
{
if(dp[l][r]!=-)
return dp[l][r];
if(l>=r)
return dp[l][r]=;
dp[l][r]=cost[r-l];
int cur=l;
for(int i=r;i>=l;i--)
{
for(;cur<i && (num[cur]-num[l-]<num[r]-num[i-]);cur++);
if(cur==i)
break;
if(num[cur]-num[l-]==num[r]-num[i-])
dp[l][r]=min(dp[l][r], cost[cur-l]+cost[r-i]+dfs(cur+, i-));
}
return dp[l][r];
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int n;
while(~scanf("%d", &n) && n)
{
num[]=;
for(int i=;i<=n;i++)
{
scanf("%d", &a[i]);
num[i]=num[i-]+(LL)a[i];
}
for(int i=;i<n;i++)
scanf("%d", &cost[i]);
for(int i=;i<=n;i++)
fill(dp[i]+i+, dp[i]+n+, -);
//memset(dp, -1, sizeof(dp));
printf("%d\n", dfs(, n));
}
return ;
}
HDOJ 4960 记忆化搜索
② 区间dp
结构体里有 SUM和NUM记录 左或右 NUM堆合起来 合成总值为SUM的
左边从1开始往右 右边从n开始往左
Lsum==Rsum了就分别把Lsum合起来 Rsum合起来 分别存进L和R 然后继续往中间
Ltmp和Rtmp分别记录左边和右边分别合到哪里了
L R 搞完以后 按顺序把 L 中间 R 放进final (注意中间)
因为对称 所以只要 dp final 的一半就够了
dp[i]=min(dp[i], dp[j]+cost[左个数]+cost[右个数]);
最后要注意合了 i堆之后 把剩下的全合起来的情况
ans=min(ans, dp[i]+cost[剩下堆数]);
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cctype>
#include <cmath>
#include <string>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
#include <queue>
#include <stack>
#include <vector>
#include <deque>
#include <set>
#include <map>
typedef long long LL;
typedef long double LD;
#define pi acos(-1.0)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
typedef pair<int, int> PI;
typedef pair<int, PI> PP;
#ifdef _WIN32
#define LLD "%I64d"
#else
#define LLD "%lld"
#endif
//#pragma comment(linker, "/STACK:1024000000,1024000000")
//LL quick(LL a, LL b){LL ans=1;while(b){if(b & 1)ans*=a;a=a*a;b>>=1;}return ans;}
//inline int read(){char ch=' ';int ans=0;while(ch<'0' || ch>'9')ch=getchar();while(ch<='9' && ch>='0'){ans=ans*10+ch-'0';ch=getchar();}return ans;}
inline void print(LL x){printf(LLD, x);puts("");}
//inline void read(double &x){char c = getchar();while(c < '0') c = getchar();x = c - '0'; c = getchar();while(c >= '0'){x = x * 10 + (c - '0'); c = getchar();}} struct node
{
LL SUM;
int NUM;
}L[], R[], final[];
LL dp[];
int a[];
int cost[];
int Ltop, Rtop, top;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int n;
while(~scanf("%d", &n) && n)
{
memset(L, , sizeof(L));
memset(R, , sizeof(R));
memset(final, , sizeof(final));
memset(a, , sizeof(a));
memset(cost, , sizeof(cost));
for(int i=;i<=n;i++)
scanf("%d", &a[i]);
for(int i=;i<=n;i++)
scanf("%d", &cost[i]); LL Lsum=a[], Rsum=a[n];
int Lnum=, Rnum=;
Ltop=Rtop=;
int Ltmp=, Rtmp=n;
for(int i=, j=n; i<j;)
{
while(Lsum!=Rsum)
{
if(i==j)
break;
if(Lsum<Rsum)
{
Lnum++;
Lsum+=a[++i];
}
else if(Rsum<Lsum)
{
Rnum++;
Rsum+=a[--j];
}
}
if(Lsum==Rsum)
{
L[Ltop].SUM=Lsum, L[Ltop++].NUM=Lnum;
R[Rtop].SUM=Rsum, R[Rtop++].NUM=Rnum;
Lsum=a[++i];
Rsum=a[--j];
Lnum=Rnum=;
Ltmp=i;
Rtmp=j;
}
}
top=;
for(int i=;i<Ltop;i++)
final[++top]=L[i];
if(Ltmp<=Rtmp)
{
int sum=;
for(int i=Ltmp;i<=Rtmp;i++)
sum+=a[i];
final[++top].SUM=sum, final[top].NUM=Rtmp-Ltmp+;
}
for(int i=Rtop-;i>=;i--)
final[++top]=R[i];
for(int i=;i<=top/;i++)
{
int tmp1=final[i].NUM, tmp2=final[top-i+].NUM;
dp[i]=LLONG_MAX;
for(int j=i-;j>=;j--)
{
dp[i]=min(dp[i], dp[j]+cost[tmp1]+cost[tmp2]);
tmp1+=final[j].NUM;
tmp2+=final[top-j+].NUM;
}
}
LL minn=LLONG_MAX;
LL ans=n;
for(int i=;i<=top/;i++)
{
minn=min(minn, dp[i]+cost[ans]);
ans-=final[i+].NUM+final[top-i].NUM;
}
print(minn);
}
return ;
}
HDOJ 4960 区间dp
[dp]HDOJ4960 Another OCD Patient的更多相关文章
- hdu 4960 Another OCD Patient(dp)
Another OCD Patient Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Ot ...
- HDU4960Another OCD Patient(间隙dp,后座DP)
Another OCD Patient Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Ot ...
- HDU 4960 Another OCD Patient(记忆化搜索)
HDU 4960 Another OCD Patient pid=4960" target="_blank" style="">题目链接 记忆化 ...
- hdu 4960 Another OCD Patient (最短路 解法
http://acm.hdu.edu.cn/showproblem.php?pid=4960 2014 Multi-University Training Contest 9 Another OCD ...
- [hdu4960]Another OCD Patient(区间dp)
题意:给出n个数,把这n个数合成一个对称的集合.每个数只能合并一次. 解题关键:区间dp,dp[l][r]表示l-r区间内满足条件的最大值.vi是大于0的,所以可以直接双指针确定. 转移方程:$dp[ ...
- HDU 4960 Another OCD Patient 简单DP
思路: 因为是对称的,所以如果两段是对称的,那么一段的前缀和一定等于另一段的后缀和.根据这个性质,我们可以预处理出这个数列的对称点对.然后最后一个对称段是从哪里开始的,做n^2的DP就可以了. 代码: ...
- HDU_4960 2014多校9 Another OCD Patient DP
其实现在想起来是个巨简单的DP,模型就跟LCS很像,比赛的时候居然没想出来,在聪哥提醒下还卡了个地方 就是说给定一串n个数字的序列,可以连续合并,最终使得序列是回文的,题目也给定了合并数字所需的代价, ...
- 【HDU4960】Another OCD Patient
题意 给出一个长度为n的整数序列.可以将一段连续的序列进行合并.合并的长度不同代价不同.问付出最少多少代价可以将这个序列变成一个对称的序列.n<=5000 分析 一看题感觉是个dp很好写啊.f[ ...
- HDU4960(SummerTrainingDay03-F dp)
Another OCD Patient Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Ot ...
随机推荐
- files_dir
一.opendir() —— 打开目录 opendir( 打开的当前目录 ); 二.closedir() —— 关闭目录 三.readdir() —— 返回目录中的各个元素,返回上一个并且指向 ...
- 第五篇、常用的SQL语句和函数介绍
简介: 在使用到sqlite3的时候,常常需要写一些SQL语句,现将常用到的部分语句稍微总结以下,由于个人习惯,关键字用大写. 附: /*简单约束*/ CREATE TABLE IF NOT EXIS ...
- OC2_数组操作
// // main.m // OC2_数组操作 // // Created by zhangxueming on 15/6/11. // Copyright (c) 2015年 zhangxuemi ...
- oracle创建存储过程并返回结果集(附C#调用代码)
使用存储过程中,最常用的莫过于查询数据表,并返回结果集. 在SQL SERVER 中,这类操作最简单,通过简单的select * from xx 即可完成.但是在Oracle中并不支持这种写法,那么我 ...
- 07_Java8新增的Lambda表达式
[Lambda表达式概述] Lambda表达式支持将代码块作为方法参数,Lambda表达式允许将使用简洁的代码来创建只有一个抽象方法的接口的实例.(这种接口称为函数式接口) [入门实例] packag ...
- 16_会话技术_Session
[Session简述] * 在Web开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下),因此,在需要保存用户数据时,服务 ...
- Jquery-Mobile滚动事件
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> < ...
- 点击按钮文字变成input框,点击保存变成文字
<!DOCTYPE html><html lang="en"> <head> <meta http-equiv="Content ...
- opensuse13.1 双屏幕扩展
最近搞一项j2eeweb工程,想要使用Linux平台编写程序.对比Ubuntu 14.04.Redhat.openSUSE,选择了最后这个. 安装的时候将/boot只分了100M,后来空间不足软件都安 ...
- linux 源码安装软件原理
make 与 configure 在使用类似 gcc 的编译器来进行编译的过程并不简单,因为一套软件并不会仅有一支程序,而是有一堆程序码文件.所以除了每个主程序与副程序均需要写上一笔编译过程的命令外, ...