zoukankan      html  css  js  c++  java
  • [题解] cogs 2240 架设电话线路

    http://cogs.pro:8080/cogs/problem/problem.php?pid=2240

    与洛谷P2885几乎一致,https://www.luogu.org/problemnew/show/P2885,双倍经验。

    定义dp[i][j]表示前i棵树的最大花费并且第i 棵树高度为j的。

    我们可以想到这某一棵树的高度与它前边的树有直接的关系,不难有一种想法。

    枚举第几棵树1->n

    枚举每棵树的高度$h[i]-> max { h[1],h[2]...h[n] } $

    枚举第i棵树前边那棵树也就是第i-1棵树的高度。

    现在我们想状态转移方程:

    当第i棵数的高度为j时,那么需要花费$(j-h[i])^2$,与前边好要有连起来那就需要找到abs(j-dp[i-1][h[i]->maxh])中的最小值。

    所以$dp[i][j]=min(dp[i][j],(j-h[i]^2+(j-dp[i-1][h[i]->maxh]) imes c))$.

    那么算法时间复杂度为$O(n imes h imes h)$.

    时间复杂度虽然比较高,奈何cogs数据比较水啊,勉强可以过。

    #include <cstdio>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    int min(int a,int b){ return a<b?a:b; }
    int n,a[100006],c,ans,f[100006][101];
    inline int read()
    {
        char c=getchar();
        int x=0;
        while(c<'0'||c>'9') c=getchar();
        while(c>='0'&&c<='9')
          x=(x<<3)+(x<<1)+c-48,c=getchar();
        return x;
    }
    int main()
    {
        freopen("phonewire.in","r",stdin);
        freopen("phonewire.out","w",stdout);
        ans=0x7fffffff;
        scanf("%d%d",&n,&c);
        for(int i=1;i<=n;i++)a[i]=read();
        for(int i=1;i<=n;i++)
            for(int j=0;j<=100;j++)
                f[i][j]=1234567890;    
        for(int i=0;i<=100;i++)f[1][i]=(i-a[1])*(i-a[1]);
        for(int i=2;i<=n;i++)
        {
            for(int j=a[i];j<=100;j++)
            {
                for(int k=a[i-1];k<=100;k++)
                {
                    f[i][j]=min(f[i][j],f[i-1][k]+(j-a[i])*(j-a[i])+abs(k-j)*c);
                }
            }
        }
        for(int i=1;i<=100;i++)ans=min(ans,f[n][i]);
        printf("%d",ans);
        fclose(stdin);fclose(stdout);
    }

    然而洛谷上不吸氧的话就需要优化一下了(以下话语来自洛谷管理---redbag)

    不难发现,每次转移是个开口向上的二次函数(可以自己算算),然后我们枚举上一棵树的高度的过程中,

    如果随着高度的增加费用增加了,就可以不用继续转移了。

    #include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
        char s;
        int k=0,base=1;
        while((s=getchar())!='-'&&s!=EOF&&!(s>='0'&&s<='9'));
        if(s==EOF)exit(0);
        if(s=='-')base=-1,s=getchar();
        while(s>='0'&&s<='9')
        {
            k=k*10+(s-'0');
            s=getchar();
        }
        return k*base;
    }
    inline void write(int x)
    {
        if(x<0)
        {
            putchar('-');
            write(-x);
        }
        else
        {
            if(x/10)write(x/10);
            putchar(x%10+'0');
        }
    }
    int n,c,p,x,s,mh;
    int h[100100];
    int f[100100][100];
    int main()
    {
        n=read();
        c=read();
        for (register int i=1; i<=n; i++)
        {
            h[i]=read();
            if (h[i]>mh) mh=h[i];
        }
        memset(f,1,sizeof(f));
        for (register int i=h[1]; i<=100; i++) f[1][i]=(i-h[1])*(i-h[1]);
        for (register int i=2; i<=n; i++)
        {
            for (register int j=h[i]; j<=mh; j++) //hm:电线杆的最大高度
            {
                s=(j-h[i])*(j-h[i]);//先算出来快些?
                p=233333333;
                for (register int k=h[i-1]; k<=mh; k++)
                {
                    x=f[i-1][k]+s+c*abs(k-j);
                    //下面和这一句是等效的,似乎快点?f[i][j]=min(f[i][j],x);
                    if (x<f[i][j])
                    {
                        f[i][j]=x;
                    }
                    if (x>p) break;//比上一个更多就不用转移了
                    p=x;
                }
            }
        }
        int ans=f[n][h[n]];
        for (register int i=h[n]+1; i<=100; i++) ans=min(ans,f[n][i]); //找答案
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    谷粒商城学习——P122 es分词&安装ik分词
    谷粒商城学习——P125 springboot 整合es
    谷粒商城学习——P70 概念SPU&SKU&规格参数&销售属性
    某大学渗透实录
    第五届强网杯全国网络安全挑战赛writeup
    首届北京大学信息安全综合能力竞赛writeup
    深入诈骗团队
    首届"鹤城杯"CTF网络安全挑战赛 初赛writeup
    陇原战"疫"2021网络安全大赛writeup
    2021第二届“天翼杯”网络安全攻防大赛writeup
  • 原文地址:https://www.cnblogs.com/rmy020718/p/9581584.html
Copyright © 2011-2022 走看看