理解:

http://blog.renren.com/share/263498909/1064362501

http://www.cnblogs.com/ronaflx/archive/2011/03/30/1999764.html

http://yomean.blog.163.com/blog/static/189420225201272864127683/

http://www.cnblogs.com/zxndgv/archive/2011/08/02/2125242.html

题目总结:

http://www.cnblogs.com/ronaflx/archive/2011/03/30/1999764.html

下摘自:http://www.cnblogs.com/zxndgv/archive/2011/08/02/2125242.html

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

最有代价用d[i,j]表示 

d[i,j]=min{d[i,k-1]+d[k+1,j]}+w[i,j] 

当中w[i,j]=sum[i,j] 

四边形不等式   

     w[a,c]+w[b,d]<=w[b,c]+w[a,d](a<b<c<d) 就称其满足凸四边形不等式 

决策单调性 

     w[i,j]<=w[i',j']   ([i,j]属于[i',j']) 既 i'<=i<j<=j'



于是有下面三个定理 



定理一: 假设w同一时候满足四边形不等式 和 决策单调性 ,则d也满足四边形不等式

定理二:当定理一的条件满足时,让d[i,j]取最小值的k为K[i,j],则K[i,j-1]<=K[i,j]<=K[i+1,j] 

定理三:w为凸当且仅当w[i,j]+w[i+1,j+1]<=w[i+1,j]+w[i,j+1] 



由定理三知 推断w是否为凸即推断 w[i,j+1]-w[i,j]的值随着i的添加是否递减 

于是求K值的时候K[i,j]仅仅和K[i+1,j] 和 K[i,j-1]有关。所以 能够以i-j递增为顺序递推各个状态值终于求得结果  将O(n^3)转为O(n^2)

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

注意:

注意决策单调性顺序,既要符合决策调性,也要符合题意 (!!!!)

注意枚举顺序,依据dp方程和决策单调性方程

注意初始化,防止訪问到无效状态或没处理的状态。

dp和s边界初始化,尤其是决策的上届和下届初始化。

例题1:

石子合并问题:hdu 3506

dp[i][j] = min{dp[i][k] + dp[k + 1][j] + cost[i, j] }, i <= k <= j - 1 , cost[i][j] = sum[j] - sum[i - 1]

s[i][j - 1] <= s[i][j] <= s[i + 1][j]

//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)
//OUTPUT
#define WI(n) printf("%d\n", n)
#define WS(s) printf("%s\n", s) typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int maxn = 2010; int dp[maxn][maxn], s[maxn][maxn];
int w[maxn][maxn]; int n, m;
int val[maxn];
int sum[maxn]; ///求dp最小值
///枚举 区间 由小到大
void solve()
{
// memset(dp, 0, sizeof(dp));///初始化无效值
FE(i, 1, 2 * n)
{
dp[i][i] = 0;
s[i][i] = i;/// 初始化决策下届,为0
}
FE(len, 2, n)
{
for (int i = 2 * n - len; i >= 1; i--)
{
int j = i + len - 1; dp[i][j] = INF;
int a = s[i][j - 1], b = s[i + 1][j];
int cost = sum[j] - sum[i - 1];
for (int k = a; k <= b; k++)
{
if (dp[i][j] > dp[i][k] + dp[k + 1][j] + cost)
{
dp[i][j] = dp[i][k] + dp[k + 1][j] + cost;
s[i][j] = k;
}
}
}
}
} int main ()
{
while (~RI(n))
{
FE(i, 1, n) RI(val[i]), val[i + n] = val[i];;
FE(i, 1, 2 * n) sum[i] = sum[i - 1] + val[i];
// pre();
solve();
int ans = INF;
FE(i, 1, n)
{
if (ans > dp[i][n + i - 1])
ans = dp[i][n + i - 1];
}
printf("%d\n", ans);
}
return 0;
}

例题2:邮局问题:

id=1160">poj 1160

1:注意此法的 i 和 j 顺序与寻常不同

此时决策区间为:s[i - 1][j] <= s[i][j] <= s[i][j + 1] (!!!)

详细见凝视:

//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)
//OUTPUT
#define WI(n) printf("%d\n", n)
#define WS(s) printf("%s\n", s) typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int maxn= 1000010; int dp[33][333], s[33][333];
int w[333][333]; int n, m;
int val[333];
int sum[333];
///dp[i][j] = min{dp[i - 1][k] + w[k + 1][j]}, i - 1 <= k <= j - 1
///一般要求 i <= j (!!)
///s[i - 1][j] <= s[i][j] <= s[i][j + 1] (! ! )
///注意决策单调性顺序,既要符合决策调性,也要符合题意 (!!!!)
///注意枚举顺序,依据dp方程和决策单调性方程
///注意初始化,防止訪问到无效状态或没处理的状态。dp和s边界初始化。尤其是决策的上届和下届初始化。 void pre()
{
for(int i = 1; i <= n; i ++) //这里有一个递推公式能够进行预处理
{
w[i][i] = 0;
for(int j = i + 1; j <= n; j ++)
{
int mid = (j + i) >> 1;
w[i][j] = w[i][j - 1] + val[j] - val[mid];
// int x = sum[j] - sum[mid] - val[mid] * (j - mid);
// x += val[mid] * (mid - i) - (sum[mid - 1] - sum[i - 1]);
}
}
} ///求dp最小值
///枚举i从小到大
///再枚举j从大到小
void solve()
{
memset(dp, 0, sizeof(dp));///初始化无效值
FE(i, 1, n)
{
dp[1][i] = w[1][i];
s[1][i] = 0;/// 初始化决策下届,为0
}
FE(i, 2, m)
{
//s[1][i] = 0;
s[i][n + 1] = n;///初始化决策上届
for (int j = n; j >= i; j--)
{
int tmp = dp[i][j] = INF;///初始化最优值
int a = s[i - 1][j], b = s[i][j + 1];
//a = max(a, i - 1); b = min(b, j - 1); // i - 1 <= k <= j - 1
for (int k = a; k <= b; k++) ///保证枚举到的都是有效状态,且都已计算过
{
if (tmp > dp[i - 1][k] + w[k + 1][j])
{
tmp = dp[i - 1][k] + w[k + 1][j];
s[i][j] = k;
}
}
dp[i][j] = tmp;
}
}
} int main ()
{
while (~RII(n, m))
{
FE(i, 1, n) RI(val[i]), sum[i] = sum[i - 1] + val[i];
pre();
solve();
printf("%d\n", dp[m][n]);
}
return 0;
}

2:-详细见凝视

此时决策区间为:s[i][j - 1] <= s[i][j] <= s[i + 1][j] (!!!)

//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)
//OUTPUT
#define WI(n) printf("%d\n", n)
#define WS(s) printf("%s\n", s) typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int maxn= 1000010; int dp[333][33], s[333][33];
int w[333][333]; int n, m;
int val[333];
int sum[333];
///dp[i][j] = min{dp[k][j - 1] + w[k + 1][j]}, j - 1 <= k <= i - 1
///此处i>=j
///s[i][j - 1] <= s[i][j] <= s[i + 1][j] (!! )
///注意决策单调性顺序,既要符合决策调性,也要符合题意 (!!!!)
///注意枚举顺序。依据dp方程和决策单调性方程
///注意初始化。防止訪问到无效状态或没处理的状态。 dp和s边界初始化,尤其是决策的上届和下届初始化。 void pre()
{
for(int i = 1; i <= n; i ++) //这里有一个递推公式能够进行预处理
{
w[i][i] = 0;
for(int j = i + 1; j <= n; j ++)
{
int mid = (j + i) >> 1;
w[i][j] = w[i][j - 1] + val[j] - val[mid];
}
}
} ///求dp最小值
///枚举i从小到大
///再枚举j从大到小
void solve()
{
memset(dp, 0, sizeof(dp));///初始化无效值
FE(i, 1, n)
{
dp[i][1] = w[1][i];
s[i][1] = 0;/// 初始化决策下届,为0
}
FE(i, 2, m)
{
//s[i][1] = 0;
s[n + 1][i] = n;///初始化决策上届
for (int j = n; j >= i; j--)
{
int tmp = dp[j][i] = INF;///初始化最优值
int a = s[j][i - 1], b = s[j + 1][i];
//a = max(a, i - 1); b = min(b, j - 1);
for (int k = a; k <= b; k++) ///保证枚举到的都是有效状态,且都已计算过
{
if (tmp > dp[k][i - 1] + w[k + 1][j])
{
tmp = dp[k][i - 1] + w[k + 1][j];
s[j][i] = k;
}
}
dp[j][i] = tmp;
}
}
} int main ()
{
while (~RII(n, m))
{
FE(i, 1, n) RI(val[i]);
pre();
solve();
printf("%d\n", dp[n][m]);
}
return 0;
}

四边形优化dp的更多相关文章

  1. HDU 2829 Lawrence(四边形优化DP O(n^2))

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2829 题目大意:有一段铁路有n个站,每个站可以往其他站运送粮草,现在要炸掉m条路使得粮草补给最小,粮草 ...

  2. HDOJ 3516 Tree Construction 四边形优化dp

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=3516 题意: 大概就是给你个下凸包的左侧,然后让你用平行于坐标轴的线段构造一棵树,并且这棵树的总曼哈顿 ...

  3. hdu2829 四边形优化dp

    Lawrence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  4. [NOI2009]诗人小G 四边形优化DP

    题目传送门 f[i] = min(f[j] + val(i,j); 其中val(i,j) 满足 四边形dp策略. 代码: #include<bits/stdc++.h> using nam ...

  5. zoj 2860 四边形优化dp

    Breaking Strings Time Limit: 2 Seconds        Memory Limit: 65536 KB A certain string-processing lan ...

  6. HDU3507 Print Article(斜率优化dp)

    前几天做多校,知道了这世界上存在dp的优化这样的说法,了解了四边形优化dp,所以今天顺带做一道典型的斜率优化,在百度打斜率优化dp,首先弹出来的就是下面这个网址:http://www.cnblogs. ...

  7. hdu 2829 Lawrence(四边形不等式优化dp)

    T. E. Lawrence was a controversial figure during World War I. He was a British officer who served in ...

  8. BZOJ1563/洛谷P1912 诗人小G 【四边形不等式优化dp】

    题目链接 洛谷P1912[原题,需输出方案] BZOJ1563[无SPJ,只需输出结果] 题解 四边形不等式 什么是四边形不等式? 一个定义域在整数上的函数\(val(i,j)\),满足对\(\for ...

  9. HDU 3506 (环形石子合并)区间dp+四边形优化

    Monkey Party Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Tot ...

随机推荐

  1. Codeforces Round #213 (Div. 1) B - Free Market 思维+背包 好题

    B - Free Market 思路:这个题怎么说呢,迷惑性很大,题目里说了交换了两个集合的时候如果有相同元素不能交换,感觉如果没 这句话能很快写出来, 其实当交换的两个集合有重复元素的时候只要交换那 ...

  2. 分布式系统的一致性算法------《Designing Data-Intensive Applications》读书笔记13

    一致性算法是分布式系统中最重要的问题之一.表面上看,这似乎很简单,只是让几个节点在某些方面达成一致.在本篇之中,会带大家完整的梳理分布式系统之中的共识算法,来更加深刻的理解分布式系统的设计. 1.原子 ...

  3. ubuntu下安装和破解navicat的方法

    ubuntu下安装和破解navicat的方法 之前我也在苦苦搜寻ubuntu完美破解navicat的方法,但是大家都说是删除掉~/.Navicat,就可以续用,的确是这样,但是很麻烦. 于是我找到了一 ...

  4. [代码审计]DM企业建站系统v201710 sql注入漏洞分析 | 新版v201712依旧存在sql注入

    0x00 前言 本来呢,这套CMS都不想审的了.下载下来打开一看,各种debug注释,排版烂的不行. 贴几个页面看看 感觉像是新手练手的,没有审下去的欲望了. 但想了想,我tm就是新手啊,然后就继续看 ...

  5. eclipse 背景颜色

    步骤阅读 3 本例使用的背景色是喜大普奔的豆沙绿,比较柔和 设置为:色调:85.饱和度:120.亮度:208 即可,据说长时间使用可以缓解眼疲劳哦. (吐槽:开什么玩笑,远离编程才能缓解眼疲劳好吗)

  6. [ 原创 ] Java基础2--构造方法的继承和重载

    1.构造方法的重载是指同一个类中定义不同参数的多个构造方法,已完成不同情况下对象的初始化. 例如: Point(); Point(x); Point(x,y); 2.一个类的若干个构造方法之间可以相互 ...

  7. windows下thrift的使用(python)

    1.下载thrift,下载地址:http://archive.apache.org/dist/thrift/0.9.3/ 2.在编写python的thrift代码时,需要先安装thrift modul ...

  8. PHP 笔记——文件引用

    1. 文件路径 "文件路径"指的是被包含文件所在的绝对路径或相对路径. 在相对路径中,"./"表示当前目录,"../"表示当前目录的上级目录 ...

  9. Codeforces Round #463

    A - Palindromic Supersequence /* 题目大意:给出一个串,构造一个包含该串的回文串 */ #include <cstdio> #include <alg ...

  10. java多线程技术之八(锁机制)

    Lock是java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作,它能以更优雅的方式处理线程同步问题,我 ...