CF #38 Lets Go Rolling!

题意是,给出n个点对(xi, ci),划分成若干段,每段[i..j]的代价是ci+{sum(xk-xi),i<=k<=j}。问说如何划分使得代价最小。

用DP,枚举第m+1段中的第m段,然后dp[i] =min{ dp[j] + cost(i, j) },转移的复杂度是O(n),状态的复杂度是O(n),总复杂度是O(n^2),不过用上类似单调队列优化的多重背包问题,可以把这题的复杂度优化到O(n)的。

代码
#include <iostream>
#include
<string>
#include
<stdio.h>
#include
<stdlib.h>
#include
<algorithm>
#include
<string.h>
#include
<vector>
#include
<math.h>
#include
<map>
#include
<time.h>
#include
<queue>
#include
<set>
using namespace std;

typedef __int64 int64;

const int MAX = 3005;

int n;
int64 cost[MAX][MAX];
int64 dp[MAX];

struct NODE
{
int x, c;
NODE() {}
NODE(
int _x, int _c) : x(_x), c(_c) {}
bool operator < (const NODE &t) const
{
return x < t.x;
}
}node[MAX];

void ready()
{
//make the cost
memset(cost, 0, sizeof(cost));
for(int i = 1; i <= n; i++) for(int j = i + 1; j <= n; j++)
{
cost[i][j]
= cost[i][j - 1] + node[j].x - node[i].x;
//printf("%d->%d %d\n", i, j, cost[i][j]);
}
}

int64 go()
{
for(int i = 1; i <= n; i++) dp[i] = 1LL << 60;
dp[
0] = 0;
for(int i = 1; i <= n; i++)
{
for(int k = 0; k <= i - 1; k++)
{
int64 t
= dp[k] + cost[k + 1][i] + node[k + 1].c;
if(t < dp[i]) dp[i] = t;
}
}
return dp[n];
}

int main()
{
while(scanf("%d", &n) != EOF)
{
for(int i = 1; i <= n; i++) scanf("%d%d", &node[i].x, &node[i].c);
sort(node
+ 1, node + n + 1);
ready();
printf(
"%I64d\n", go());
}
}



/*
3
2 3
3 4
1 2

4
1 7
3 1
5 10
6 1
*/

 

posted @ 2010-11-02 10:01  litstrong  阅读(190)  评论(0编辑  收藏  举报