河南省第十一届ACM大学生程序设计竞赛——C-山区修路

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40788630/article/details/88902310

题目描述:

SNJ位于HB省西部一片群峰耸立的高大山地,横亘于A江、B水之间,方圆数千平方公里,相传上古的神医在此搭架上山采药而得名。景区山峰均在海拔3000米以上,堪称"华中屋脊"。SNJ是以秀绿的亚高山自然风光,多样的动植物种,人与自然和谐共存为主题的森林生态区。
SNJ处于中国地势第二阶梯的东部边缘,由大巴山脉东延的余脉组成中高山地貌,区内山体高大,高低不平。 交通十分不便。
最近,HB省决定修一条从YC市通往SNJ风景区的高速公路。经过勘测分析,途中需要经过高度分别为H1,H2,……,Hn的N个山区。由于高低不平,除正常的修路开支外,每段还要多出高度差|Hi - Hi-1|*X万元的斜坡费用。Dr. Kong 决定通过填高一些区域的高度来降低总的费用。当然填高也是需要一些费用的。每填高Y单位,需要付出Y^2万元费用。
你能否帮Dr. Kong做出一个规划,通过部分填高工程改造,使得总的费用降下来。

输入描述:

第一行: T 表示以下有T组测试数据( 1≤ T ≤8 )
对每组测试数据,   
第一行:N  X(2 ≤ N ≤100,000   1≤ X ≤100)
第二行:N个整数,分别表示N个区域的高度Hi( 1<=Hi<=100 , i=1…. n)

输出描述:

对每组测试数据,输出占一行,一个整数,即经过部分填高工程改造后的最少费用。

样例输入:

复制

1
5 2
2 3 5 1 4

样例输出:

15

这是一个动态规划类型的题,虽然时间复杂度为(100000*100*100)但是测试数据很弱,能测过

首先创建一个动态数组dp[i][j]代表的是第i个山头高为j,dp[i][j]的值就是从第一个山头修到第i个山头(此时山头高度为j)的最小花费,dp[i][j]只和dp[i-1][k](h[i-1]<=k<=100)有关。最后的最小花费只需要在dp[n][j]中寻找最小的

需要注意的是,山头只可以垫高不可以挖低(我就卡在这半个小时!难受)

#include<iostream>
#include<algorithm>
using namespace std;
int dp[100005][101]={0},h[100005];
int INF=99999999;
int main(){
	int t,n,x;
	cin>>t;
	while(t--){
		cin>>n>>x;
		fill(dp[0],dp[0]+n*101,INF);//初始化 
		for(int i=1;i<=n;i++){
			cin>>h[i];
		}
		for(int j=h[1];j<100;j++){//先算第一个山区 
			dp[1][j]=min(dp[1][j],(j-h[1])*(j-h[1])); 
		}
		for(int i=2;i<=n;i++){//从第二个山头开始算 
			for(int j=h[i];j<=100;j++){//只可垫高,所以从山头本身的高度开始循环 
				int bj=INF;
				for(int k=h[i-1];k<=100;k++){
					bj=min(bj,abs(j-k)*x+dp[i-1][k]); //bj代表的是——从第i-1个山头到第i个山头之间(此时高度为j)的花费 + 从第一个上头修路到第i-1个山头(此时高度为k)的最小花费 
				}
				dp[i][j]=bj+(j-h[i])*(j-h[i]); //dp[i][j]应该是bj加上此时第i个山头垫高的花费 
			}
		}
		int max1=INF;
		for(int i=h[n];i<101;i++){//从第n个山头可能的高度中找到最小的 
			max1=min(max1,dp[n][i]);
		}
		cout<<max1<<endl; 
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40788630/article/details/88902310