您的位置:首页 > 编程语言 > Go语言

CF #38 Lets Go Rolling!

2010-11-02 10:01 155 查看
题意是,给出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
;
}

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
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: