博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDU 3480 Division
阅读量:5279 次
发布时间:2019-06-14

本文共 3747 字,大约阅读时间需要 12 分钟。

HDU_3480

    首先,一个贪心的思路就是如果将元素排个序,选择的一定是连续的区间,因为如果选了两个值,那么这个区间就可以选两个值之间的任何一个值,这样是不会改变这个区间的cost的。

    如果用w[i][j]表示(a[j]-a[i])*(a[j]-a[i]),写出状态转移方程后会得到f[i][j]=min{f[i-1][k-1]+w[k,j]},这个和POJ_1160的状态转移方程是一样的,如果我们能够证明w为凸,那么这个题就可以用四边形不等式优化。

    由于w[i+1][j]-w[i][j]=(a[i]-a[i+1])*(2*a[j]-a[i+1]-a[i]),这个表达式是随着j的增加单调递减的,所以就有w[i+1][j+1]-w[i][j+1]<=w[i+1][j]-w[i][j],也就是w[i][j]+w[i+1][j+1]<=w[i][j+1]+w[i+1][j],所以w是凸的,进而我们就可以放心地使用四边形不等式优化dp了。

    其实,如果我们把状态转移方程写成f[i][j]=min{f[i-1][k-1]+ (a[j]-a[k])*(a[j]-a[k])}的话,不妨假设k的取值x、y满足x<y,且y要比x优,这时就能化简成a[j]>(a[y]*a[y]-a[x]*a[x]+f[i-1][y-1]-f[i-1][x-1])/(2*a[y]-2*a[x]),这样就又变成能够使用斜率优化了,而且用斜率优化比较好用滚动数组实现,能节省不少空间。

//四边形不等式优化dp #include
#include
#include
#define MAXD 10010 #define INF 0x3f3f3f3f int N, M, a[MAXD], f[MAXD][MAXD], K[MAXD][MAXD]; int cmp(const void *_p, const void *_q) {
int *p = (int *)_p, *q = (int *)_q; return *p - *q; } int getw(int x, int y) {
return (a[y] - a[x]) * (a[y] - a[x]); } void init() {
int i, j, k; scanf("%d%d", &N, &M); for(i = 1; i <= N; i ++) scanf("%d", &a[i]); } void solve() {
int i, j, k, p, t; qsort(a + 1, N, sizeof(a[0]), cmp); for(i = 0; i <= N; i ++) {
f[i][i] = 0; K[i][i] = i; } for(i = M + 2; i <= N; i ++) K[M + 1][i] = i; for(p = 1; p <= N - M; p ++) {
f[0][p] = INF; for(i = 1; i <= M; i ++) {
j = i + p; f[i][j] = INF; for(k = K[i][j - 1]; k <= K[i + 1][j]; k ++) {
t = f[i - 1][k - 1] + getw(k, j); if(t < f[i][j]) {
f[i][j] = t; K[i][j] = k; } } } } printf("%d\n", f[M][N]); } int main() {
int t, tt; scanf("%d", &t); for(tt = 0; tt < t; tt ++) {
init(); printf("Case %d: ", tt + 1); if(M >= N) printf("0\n"); else solve(); } return 0; }

 

//斜率优化+单调队列 #include
#include
#include
#define MAXD 10010 int N, M, a[MAXD], wa[MAXD], wb[MAXD], *f, *g, q[MAXD]; int cmp(const void *_p, const void *_q) {
int *p = (int *)_p, *q = (int *)_q; return *p - *q; } void init() {
int i, j, k; scanf("%d%d", &N, &M); for(i = 1; i <= N; i ++) scanf("%d", &a[i]); } int getw(int x, int y) {
return (a[y] - a[x]) * (a[y] - a[x]); } int getf(int i) {
return a[i] * a[i] + g[i - 1]; } void solve() {
int i, j, k, front, rear, x, y, z, *t; qsort(a + 1, N, sizeof(a[0]), cmp); f = wa, g = wb; for(i = 1; i <= N; i ++) g[i] = getw(1, i); for(i = 2; i <= M; i ++) {
front = rear = 0; q[rear ++] = i; for(j = i; j <= N; j ++) {
while(front < rear - 1) {
x = q[front], y = q[front + 1]; if(a[j] * 2 * (a[y] - a[x]) < getf(y) - getf(x)) break; ++ front; } x = q[front]; f[j] = g[x - 1] + getw(x, j); if(j < N) {
q[rear] = j + 1; for(k = rear - 1; k > front; k --) {
x = q[k - 1], y = q[k], z = q[k + 1]; if((getf(y) - getf(x)) * (a[z] - a[y]) < (getf(z) - getf(y)) * (a[y] - a[x])) break; q[rear = k] = q[k + 1]; } ++ rear; } } t = f, f = g, g = t; } printf("%d\n", g[N]); } int main() {
int t, tt; scanf("%d", &t); for(tt = 0; tt < t; tt ++) {
init(); printf("Case %d: ", tt + 1); if(M >= N) printf("0\n"); else solve(); } return 0; }

转载于:https://www.cnblogs.com/staginner/archive/2012/03/13/2394329.html

你可能感兴趣的文章
Linux常用命令——关机与重启命令
查看>>
10分钟快速理解依赖注入
查看>>
转:远程桌面提示:由于网络错误,连接被中断,请重新连接到远程计算机
查看>>
截图+贴图工具 - Snipaste
查看>>
python语法学习之数据结构
查看>>
Android学习CursorWrapper与Decorator模式
查看>>
【SQL】视图
查看>>
【编程之美】2.8 找符合条件的整数
查看>>
Android-多线程:AsyncTask多线程使用
查看>>
poj1062 昂贵的礼物(dijkstra+枚举)
查看>>
NOIP练习赛题目1
查看>>
找出全部最长连续反复子串及其个数
查看>>
从数据集输出艺术家
查看>>
Linux云计算面试会被问到的常见问题,linux运维课程学习
查看>>
Spring Boot实践教程:开篇
查看>>
感动世界的英雄妈妈
查看>>
DML语言DDL
查看>>
专题讨论:敏捷软件开发和传统软件工程
查看>>
深入探究VC —— 链接器link.exe(4)【转】http://blog.csdn.net/wangningyu/article/details/4849452...
查看>>
mfc的WM_PAINT笔记
查看>>