openjudge telephone wire

2373:Telephone Wire

  • 查看
  • 提交
  • 统计
  • 提问
总时间限制: 
10000ms 
单个测试点时间限制: 
1000ms 
内存限制: 
65536kB
描述
Farmer John's cows are getting restless about their poor telephone service; they want FJ to replace the old telephone wire with new, more efficient wire. The new wiring will utilize N (2 <= N <= 100,000) already-installed telephone poles, each with some height_i meters (1 <= height_i <= 100). The new wire will connect the tops of each pair of adjacent poles and will incur a penalty cost C * the two poles' height difference for each section of wire where the poles are of different heights (1 <= C <= 100). The poles, of course, are in a certain sequence and can not be moved.

Farmer John figures that if he makes some poles taller he can reduce his penalties, though with some other additional cost. He can add an integer X number of meters to a pole at a cost of X^2.

Help Farmer John determine the cheapest combination of growing pole heights and connecting wire so that the cows can get their new and improved service.
输入
* Line 1: Two space-separated integers: N and C

* Lines 2..N+1: Line i+1 contains a single integer: height_i
输出
* Line 1: The minimum total amount of money that it will cost Farmer John to attach the new telephone wire.
样例输入
5 2
2
3
5
1
4
样例输出
15
提示
INPUT DETAILS:

There are 5 telephone poles, and the vertical distance penalty is $2/meter. The poles initially have heights of 2, 3, 5, 1, and 4, respectively.

OUTPUT DETAILS:

The best way is for Farmer John to raise the first pole by 1 unit and the fourth pole by 2 units, making the heights (in order) 3, 3, 5, 3, and 4. This costs $5. The remaining wiring will cost $2*(0+2+2+1) = $10, for a total of $15.
来源

USACO November 2007 Gold


题目大意:农民FJ要改进他农场的电话系统,他要把他的N个电线杆进行改造。这N个电线杆的是呈线性分布的d[1-N],对于相邻的两根电线杆其改造费用是C * (两个电线杆的高度差)。另外,农民FJ也可以对任意的电线杆进行加长(比如加长X),但是要另外花费加长的费用X^2。现在你的任务是求出农民FJ改造农场所需要的最少的费用是是多少?


60分程序

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int n,c,h[100003],f[100003][103];
int i,j,k,maxn,ans;
int main()
{
scanf("%d%d",&n,&c);
for (i=1;i<=n;i++)
{
scanf("%d",&h[i]);
maxn=max(maxn,h[i]);
}
memset(f,127/3,sizeof(f));
for (i=h[1];i<=maxn;i++)
f[1][i]=(i-h[1])*(i-h[1]);
for (i=2;i<=n;i++)
for (j=h[i];j<=maxn;j++)
 for (k=h[i-1];k<=maxn;k++)
  {
  int x=f[i-1][k]+c*abs(j-k)+(j-h[i])*(j-h[i]);
   f[i][j]=min(f[i][j],x);
          }
    ans=1000000000;
    for (i=h[n];i<=max(h[n-1],h[n]);i++)
      ans=min(f[n][i],ans);
printf("%d",ans); 
}//这个思路好想好实现但是100000×100×100肯定会超时,f[i][j]=min( (j-a[i])^2+f[i-1][k]+|j-k|*c ) (j>=a[i])这个是基础,在这个基础上进行优化。

表示自己比较水,没能想到优化的方法,于是参考了一下网上的思路:

DP
设f[i][j]表示第i个电线杆高度为j时的最小花费,
DP方程为f[i][j]=min( (j-a[i])^2+f[i-1][k]+|j-k|*c )
直接根据这条方程做的话复杂度是100000*100*100,明显会超时.
可以将方程进行化简:
f[i][j]=min( (j-a[i])^2+f[i-1][k]+|j-k|*c ) (j>=a[i])
       =(j-a[i])^2+j*c+min(f[i-1][k]-k*c) (j>=k)
     (j-a[i])^2-j*c+min(f[i-1][k]+k*c) (j<k)
设low[j]=min(f[i-1][k]-k*c) (j>=k)
high[j]=min(f[i-1][k]+k*c) (j<k)
方程就变为f[i][j]=(j-a[i])^2+min(high[j]-j*c,low[j]+j*c);
可以通过预处理计算先出high[j],low[j].


满分代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[100003],a[100003],n,m,i,j,c;
int high[103],low[103];
int main()
{
scanf("%d%d",&n,&c);
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
for (i=1;i<=100;i++)
if (i<a[1])
 f[i]=1000000000;
else
 f[i]=(i-a[1])*(i-a[1]); 
for (i=2;i<=n;i++)
{
int t=1000000000;
for (j=100;j>0;j--)
 high[j]=t=min(t,f[j]+j*c);//high 存储的是原方程中J<K的状态,T中存储的其实是从100 到当前高度的最优值。

   t=1000000000;
for (j=1;j<=100;j++)
{
 low[j]=t=min(t,f[j]-j*c);//刚开始我一直不明白为什么这么处理,因为理解错了这里J的含义,注意这里的J表示的是第I个电线杆的长度,而不是原始状态转移方程中的K。
 f[j]=1000000000;
    }
for (j=a[i];j<=100;j++)
{
int x,y;
x=(j-a[i])*(j-a[i])+j*c+low[j];
   y=(j-a[i])*(j-a[i])-j*c+high[j];
   f[j]=min(x,y);
}

int ans=1000000000;
for (i=1;i<=100;i++)
ans=min(ans,f[i]);
printf("%d",ans);
return 0;

你可能感兴趣的:(openjudge telephone wire)