zoukankan      html  css  js  c++  java
  • 入门OJ:简单的网络游戏

    题目描述

    在某款极具技术含量的网络游戏中,佳佳靠着他的聪明智慧垄断了游戏中的油田系统。油田里有许多油井,这些油井排成一个M*N的矩形。每个油井都有一个固定的采油量。每两个相邻的油井之间有一条公路,这些公路是油井与油井之间唯一的运油方式。佳佳的领地在油田的右方和下方,他需要把采到的油通过这些公路运输到他的领地。为了保证采到的油以最快的方式供给右方和下方的领地,对于每个油井,佳佳总是将采到的油分成非空的两部分将其中一部分沿公路一直向右运输到油田的右边界,将另一部分沿公路一直向下运输到油田的下边界。然而树大招风,网络游戏中的GM以保证游戏公平为由,要求佳佳主动贡献出K个油井。更惨的是,失去某些油井不单意味着采油量减少,这还将会导致运输线路的中断。如果佳佳贡献出了某个油井,那么所有要经过这个油井的运输任务将无法完成。佳佳想保证贡献K个油井之后自己的损失最小(损失即为失去的所有油井的采油量之和),而他希望其他的所有油井还能够像往常一样正常运输。于是他向你求救,希望你能帮助他实现他的想法。

    输入格式

    第一行有三个用空格隔开的正整数M,N和K,它们分别表示油田的长、宽和佳佳需要贡献出的油田数。以下N行中每行有M个用空格隔开的正整数。这些正整数保证不超过10000,它们描述了油田中各个油井的采油量。 输入数据保证K<=M*N,M<=60,N<=60。

    输出格式

    一个整数,表示佳佳最少要损失的采油量。


    分析题目后可以得出这样一个结论:

    设c(i,j)表示第i行前j个油井的采油量之和,那么放弃点(x,y)的油井的代价就是:c(x,y)。由于c数组当i确定的时候随j的变大单调不下降,所以我们对于第i行放弃的油井应该为从左端点开始的连续一段油井。同理对于第i列放弃的油井也应该为从上断电开始的连续一段油井。

    通过这个结论可以进一步推导:

    当前行选择的油井数必须小于等于上一行选择的油井数。

    于是我们很容易设计出这样的状态:dp(i,j,k)表示第i行选了j个油井,并且1~i行一共选了k个油井(不是题目的K)。那么我们可以列出转移方程:

    [dp[i][j][k]=Min{{}dp[i-1][l][j-k]+c[i][k]{}} ]

    其中l为上一行选择的油井数。初始状态dp(1,i,i)=c(1,i),目标状态为Min{dp(n,i,K)}。

    * 一个明显的优化是dp数组的第一维可以滚掉。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 61
    #define maxm 3601
    using namespace std;
     
    int dp[maxn][maxn][maxm],c[maxn][maxn];
    int n,m,sum;
     
    inline int read(){
        register int x(0),f(1); register char c(getchar());
        while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
        while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
     
    int main(){
        m=read(),n=read(),sum=read();
        for(register int i=1;i<=n;i++){
            for(register int j=1;j<=m;j++) c[i][j]=c[i][j-1]+read();
        }
     
        memset(dp,0x3f,sizeof dp);
        for(register int i=0;i<=m;i++) dp[1][i][i]=c[1][i];
        for(register int i=2;i<=n;i++){
            for(register int j=0;j<=min(sum,i*m);j++){
                for(register int k=0;k<=min(sum,min(m,j/i));k++){
                    for(register int l=k;l<=min(sum,min(m,(j-k)/(i-1)));l++){
                        if(j>l) dp[i][k][j]=min(dp[i][k][j],dp[i-1][l][j-k]+c[i][k]);
                    }
                }
            }
        }
        int ans=0x3f3f3f3f;
        for(register int i=0;i<=min(sum,m);i++){
            ans=min(ans,dp[n][i][sum]);
        }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    如何用conda安装软件|处理conda安装工具的动态库问题
    用 Anaconda 完美解决 Python2 和 python3 共存问题
    转录组数据库介绍
    突变注释工具SnpEff,Annovar,VEP,oncotator比较分析--转载
    BioConda--转载
    生信软件的好帮手-bioconda--转载
    一些WGS健康体检网站和公司
    基于R进行相关性分析--转载
    R语言 sub与gsub函数的区别
    Docker安装
  • 原文地址:https://www.cnblogs.com/akura/p/11045358.html
Copyright © 2011-2022 走看看