• 题解:luogu4360 锯木厂选址


    题目描述

    从山顶上到山底下沿着一条直线种植了nn棵老树。当地的政府决定把他们砍下来。为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂。

    木材只能朝山下运。山脚下有一个锯木厂。另外两个锯木厂将新修建在山路上。你必须决定在哪里修建这两个锯木厂,使得运输的费用总和最小。假定运输每公斤木材每米需要一分钱。

    你的任务是编写一个程序,从输入文件中读入树的个数和他们的重量与位置,计算最小运输费用。

    输入输出格式

    输入格式:

    输入的第一行为一个正整数nn——树的个数(2≤n≤20000)(2n20000)。树从山顶到山脚按照1,2,...,n1,2,...,n标号。

    接下来nn行,每行有两个正整数(用空格分开)。

    i+1i+1行含有:w_iwi——第ii棵树的重量(公斤为单位)和 d_idi——第ii棵树和第i+1i+1棵树之间的距离,1≤w_i≤10000,0≤d_i≤100001wi10000,0di10000。

    最后一颗树的d_ndn,表示第nn棵树到山脚的锯木厂的距离。保证所有树运到山脚的锯木厂所需要的费用小于2×10^92×109分。

    输出格式:

    输出最小的运输费用。

    输入输出样例

    输入样例#1: 复制
    9 
    1 2 
    2 1 
    3 3 
    1 1 
    3 2 
    1 6 
    2 1 
    1 2 
    1 1
    
    输出样例#1: 复制

    26

    解题思路:

    可以写出dp方程,发现满足斜率优化的特征,斜率优化

    暴力dp(能ac)

     1#include<bits/stdc++.h>
    2#define N 40000
    3using namespace std;
    4int w[N],sum[N],d[N],dis[N],n,cnt;
    5int dp[N]; 
    6void read(){
    7    scanf("%d",&n);
    8    for (int i=1;i<=n;i++)
    9        scanf("%d%d",&w[i],&d[i]);
    10    for (int i=1;i<=n;i++)
    11        sum[i]=sum[i-1]+w[i];
    12    for (int i=n;i>=1;i--)
    13        dis[i]=dis[i+1]+d[i];
    14    //for (int i=1;i<=n;i++)
    15    //    cout << dis[i] << "  " << sum[i] << endl;
    16}
    17void solve(){
    18    memset(dp,0x3f3f3f,sizeof(dp));
    19    for (int i=1;i<=n;i++)
    20        cnt+=w[i]*dis[i];
    21    //cout << cnt <<"cnt"<< endl;
    22    for (int i=1;i<=n;i++){
    23        for (int j=1;j<i;j++)
    24            dp[i]=min(dp[i],cnt-dis[i]*(sum[i]-sum[j])-dis[j]*sum[j]);
    25    }
    26    int ans=1023456789;
    27    for (int i=1;i<=n;i++)
    28        ans=min(ans,dp[i]); 
    29    cout << ans <<endl;
    30}
    31int main(){
    32    read();
    33    solve();
    34    return 0;
    35}

    斜率优化版本(比前一个快20倍):

     1#include<bits/stdc++.h>
    2#define N 40000
    3using namespace std;
    4int w[N],sum[N],d[N],dis[N],n,cnt;
    5int dp[N],q[N]; 
    6double X(int x){
    7    return sum[x]*dis[x];
    8}
    9double Y(int y){
    10    return sum[y];
    11}
    12double slope(int i,int j){
    13    return (X(i)-X(j))/(Y(i)-Y(j));
    14}
    15void read(){
    16    scanf("%d",&n);
    17    for (int i=1;i<=n;i++) scanf("%d%d",&w[i],&d[i]);
    18    for (int i=1;i<=n;i++) sum[i]=sum[i-1]+w[i];
    19    for (int i=n;i>=1;i--) dis[i]=dis[i+1]+d[i];
    20    for (int i=1;i<=n;i++) cnt+=w[i]*dis[i];
    21}
    22void solve(){
    23    memset(dp,0x3f3f3f,sizeof(dp));
    24    int l=0,r=0;
    25    for (int i=1;i<=n;i++){
    26        while (l<r && slope(q[l],q[l+1])>dis[i])
    27            l++;
    28        int j=q[l];
    29        dp[i]=cnt-dis[i]*(sum[i]-sum[j])-dis[j]*sum[j];
    30        while (l<r && slope(q[r],q[r-1])<slope(i,q[r]))
    31            r--;
    32        q[++r]=i;
    33    }
    34    int ans=1023456789;
    35    for (int i=1;i<=n;i++) ans=min(ans,dp[i]); 
    36    cout << ans <<endl;
    37}
    38int main(){
    39    read();
    40    solve();
    41    return 0;
    42}
  • 相关阅读:
    thinkphp3.2.3版本在windows本地apache环境运行正常,上传到centos服务器apache环境中出现:thinkphp 上传根目录不存在!请尝试手动创建:uploads/
    [POI2013]LUK-Triumphal arch
    【背包问题】
    2016 acm香港网络赛 A题. A+B Problem (FFT)
    tomcat部署项目的三种方式
    仿照ArrayList自己生成的MyList对象
    使用回调函数实现回文判断
    关于angularjs的model的一些问题
    关于使用Tomcat服务器出现413错误的解决办法(Request Entity Too Large)
    关于angularjs+typeahead的整合
  • 原文地址:https://www.cnblogs.com/titititing/p/9643668.html
Copyright © 2020-2023  润新知