【暑假】[深入动态规划]UVa 10618 Fixing the Great Wall
2015-08-18 22:58
399 查看
UVa 10618 Fixing the Great Wall
题目:
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=36139
思路:
数轴上有n个点需要修复,每个点有信息c,x,d 表示位于x且在t时修缮的费用是c+d*t,找一个修缮序列使n个点能全部修缮且有费用最小。
可以发现:在任意时刻,修缮完的点都是连续的,因为修缮不需要时间,将一些点“顺手”修缮了肯定不差。
d[i][j][k],表示已经将i-j个点修缮完后位于p(if (k==0) p=i;else p=j;)的花费,不知道时间怎么办呢?
:注意到每个点的花费是c+d*t ,累计花费并不一定要将每个点的花费都求出来然后相加。于是正式定义d表示该清情况下所有已知花费,每当因为移动时间耗去t所有没有访问的点u花费都会相应增加u.d*t,总花费增加sum_d*t。换句话说,这种方法根据花费的特点将单个点花费累加变成了累计未访问点在未访问时间内的花费。
当位于ijk时有两种抉择:左走i-1 j 0 或右走 i j+1 1 这就是子问题 。
答案不大于10^9 但过程中好像input中会出现超int的情况但long long空间占用太大,因此用了double,最后转成int。
代码:
题目:
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=36139
思路:
数轴上有n个点需要修复,每个点有信息c,x,d 表示位于x且在t时修缮的费用是c+d*t,找一个修缮序列使n个点能全部修缮且有费用最小。
可以发现:在任意时刻,修缮完的点都是连续的,因为修缮不需要时间,将一些点“顺手”修缮了肯定不差。
d[i][j][k],表示已经将i-j个点修缮完后位于p(if (k==0) p=i;else p=j;)的花费,不知道时间怎么办呢?
:注意到每个点的花费是c+d*t ,累计花费并不一定要将每个点的花费都求出来然后相加。于是正式定义d表示该清情况下所有已知花费,每当因为移动时间耗去t所有没有访问的点u花费都会相应增加u.d*t,总花费增加sum_d*t。换句话说,这种方法根据花费的特点将单个点花费累加变成了累计未访问点在未访问时间内的花费。
当位于ijk时有两种抉择:左走i-1 j 0 或右走 i j+1 1 这就是子问题 。
答案不大于10^9 但过程中好像input中会出现超int的情况但long long空间占用太大,因此用了double,最后转成int。
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define FOR(a,b,c) for(int a=(b);a<(c);a++) using namespace std; const int maxn = 1000 + 10; const int INF = 1e30; struct Node{ double x,c,d; bool operator <(const Node& rhs) const { return x<rhs.x; } }; Node nodes[maxn]; int n,kase; double v,x,d[maxn][maxn][2]; //d记录目前已知的所有花费 double pre_d[maxn]; int vis[maxn][maxn][2]; inline double cost(double x,double y,int i,int j) { double finished=0; if(i>j) return 0.0; if(i>=0 && j>=0) finished += pre_d[j]-pre_d[i-1]; //sum_d[i,j] return (pre_d -finished) * fabs(y-x)/v; //总花费+所有未访问的点.d*t } double dp(int i,int j,int k) { if(i==1 && j==n) return 0; // 边界 double& ans=d[i][j][k]; if(vis[i][j][k]==kase) return ans; vis[i][j][k]=kase; //记忆化搜索 ans=INF; double x=(k==0? nodes[i].x:nodes[j].x); if(i>1) ans=min(ans,dp(i-1,j,0) + cost(x,nodes[i-1].x,i,j)); if(j<n) ans=min(ans,dp(i,j+1,1) + cost(x,nodes[j+1].x,i,j)); return ans; } int main() { kase=0; memset(vis,0,sizeof(vis)); while(scanf("%d%lf%lf",&n,&v,&x)==3 && (n&&v&&x)) { ++kase; double sumc=0; FOR(i,1,n+1){ scanf("%lf%lf%lf",&nodes[i].x,&nodes[i].c,&nodes[i].d); sumc += nodes[i].c; } sort(nodes+1,nodes+n+1); pre_d[0]=0; FOR(i,1,n+1) pre_d[i]=pre_d[i-1]+nodes[i].d; //'哨兵' 如果初始点在第0个点的左或第n个点的右 //使满足判断的普遍性 nodes[0].x=-INF; nodes[n+1].x=INF; double ans= INF; FOR(i,1,n+2) if(x>nodes[i-1].x && x<nodes[i].x){ //找到起点位置处于i-1...i 然后移动向左|右点 if(i>1) ans=min(ans,dp(i-1,i-1,0)+cost(x,nodes[i-1].x,-1,-1)); if(i<=n) ans=min(ans,dp(i,i,0)+cost(x,nodes[i].x,-1,-1)); break; } printf("%0.lf\n",floor(ans + sumc)); } return 0; }
相关文章推荐
- NYOJ 2 括号配对问题 (栈 stack)
- 上传大文件,出现: 413 request Entity too Large错误的解决办法
- 四层和七层负载均衡
- matlabR2008a函数编译成dll供vc6.0调用的方法
- Android 主线程与子线程通信的几种方式
- Python Foundation - part two
- ArcGis中MapServer查询使用
- pat(A) 2-06. 数列求和(模拟摆竖式相加)
- HDU 1166 敌兵布阵 (树状数组)
- javascript 基本类型和引用类型
- 查找域控的几个常用方法
- HDU 1166 敌兵布阵 (树状数组)
- 黑马程序员------Foundatin之求单个文件的代码行数
- CDN流量放大攻击思路
- Android 利用Fiddler进行网络数据抓包
- 简单的视图切换(tag)
- Choose the best route
- Python解LeetCode 131: Palindrome Partitioning(Python中的浅复制与深复制)
- 费用流 csu1506 Double Shortest Paths
- Android--文件监控FileObserver