[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 ...
随机推荐
- PHP中foreach循环详解
首先要说的是,其实我对foreach循环的用法并不是很精通,说详解,其实也只是我自己的理解,希望对你能有点帮助 . 先来看一下foreach的语法: foreach ($array as $key=& ...
- ASP实现用年月日时分秒和两位随机数字来作为上传文件名的函数
Public Function GetNewFileName() dim ranNum dim dtNow dtNow=Now() randomize ranNum=int(90*rnd)+10 Ge ...
- Swift 2.0基本语法
内容包括:01变量&常量 02分支 03循环 04字符串 05数组 06字典 07函数 01变量&常量 //: Playground - noun: a place where peo ...
- iOS Core Animation学习总结(2)--实现自定义图层
一. 创建图层继承于CALayer,并在子类实现drawInContext方法 @interface CTLayer : CALayer @end @implementation CTLayer -( ...
- oc 基础知识
一.枚举 结构体 typedef enum{ sexMan, sexWoman }Sex; tydedef struct{ int year; int month; int da ...
- StrHelper
public class StrHelper { private static string passWord; //加密字符串 /// <summary> /// 判断输入是否数字 // ...
- Flexbox介绍
CSS3 弹性盒( Flexible Box 或 flexbox),是一种当页面需要适应不同的屏幕大小以及设备类型时确保元素拥有恰当的行为的布局方式.对于很多应用来讲,弹性盒改进了盒模型,既不使用浮动 ...
- Nwjs从入门到精通 菜鸟实践笔记【1】
最近公司有想使用Nw来开发浏览器的想法,自己一直学的PHP,在网上并没有找到太多的相关资料,所以,就自己摸索着撸一条自学笔记: 当然呢,这里记录的都是我自己学习中遇到的问题,以及收获,希望通过自己的分 ...
- ECMAScript布尔操作符
在ECMAScript中提供了Boolean()转换函数以及三个布尔操作符,这三个布尔操作符分别为逻辑非.逻辑与.逻辑或,这三个操作符通常用作于某些值的求反,比较模式等.学好这一点知识也非常的重要,奠 ...
- 点击按钮文字变成input框,点击保存变成文字
<!DOCTYPE html><html lang="en"> <head> <meta http-equiv="Content ...