• 洛谷P2066 机器分配【dp】


    洛谷P2066 机器分配【dp】

    题目链接:https://www.luogu.com.cn/problem/P2066

    题目描述

    总公司拥有高效设备M台,准备分给下属的N个分公司。各分公司若获得这些设备,可以为国家提供一定的盈利。问:如何分配这M台设备才能使国家得到的盈利最大?求出最大盈利值。其中M≤15,N≤10。分配原则:每个公司有权获得任意数目的设备,但总台数不超过设备数M。

    输入格式

    第一行有两个数,第一个数是分公司数N,第二个数是设备台数M。

    接下来是一个N*M的矩阵,表明了第 I个公司分配 J台机器的盈利。

    输出格式

    第1行为最大盈利值

    第2到第n为第i分公司分x台

    P.S.要求答案的字典序最小

    输入输出样例

    输入 #1

    3 3
    30 40 50
    20 30 50
    20 25 30
    

    输出 #1

    70
    1 1
    2 1
    3 1
    

    先不考虑字典序最小的问题,代码很好写。就是个背包

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn = 1e3;
    int n,a[maxn][maxn],f[maxn][maxn],ans[maxn][maxn];
    void print(int n, int m){//用于输出前n个公司,分配m台机器的方案
    	if(n == 0) return;
    	else{
    		print(n-1, m-ans[n][m]);//往前递归
    		printf("%d %d
    ", n, ans[n][m]);//输出公司编号和设备数
    	}
    }
    int main(){
        int n,m; scanf("%d%d",&n, &m);
        for(int i=1; i<=n; i++)for(int j=1; j<=m; j++)scanf("%d", &a[i][j]);//第i个公司分配j台机器的盈利。 
        for(int i=1; i<=n; i++)//公司
          	for(int j=1; j<=m; j++)//总共分配的机器数
         		for(int k=0; k<=j; k++)//给当前公司分配几个设备
    				if(f[i][j]<=f[i-1][j-k]+a[i][k]){
    					f[i][j] = f[i-1][j-k]+a[i][k];
    					ans[i][j] = k;//记录一下方案,前i个公司分配j台机器时,公司i获得的设备数
    				}
    	printf("%d
    ", f[n][m]);
    	print(n,m);
        return 0;
    }
    

    看这组数据:

    2 15
    1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
    1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
    

    刚才的程序输出:

    2
    1 1
    2 1
    

    但字典序最小的方案是:

    2
    1 0
    2 15
    
    

    若考虑上字典序呢,我们就让编号靠后的公司分配的机器多一点,这样前面分配的机器就少,字典序就小

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn = 1e3;
    int n,a[maxn][maxn],f[maxn][maxn],ans[maxn][maxn];
    void print(int n, int m){
    	if(n == 0) return;
    	else{
    		print(n-1, m-ans[n][m]);
    		printf("%d %d
    ", n, ans[n][m]);
    	}
    }
    int main(){
        int n,m; scanf("%d%d",&n, &m);
        for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) scanf("%d", &a[i][j]);
        for(int i=1; i<=n; i++)
          	for(int j=1; j<=m; j++)
         		for(int k=0; k<=j; k++)
    				if(f[i][j]<=f[i-1][j-k]+a[i][k]){//只有这不同,小于等于
    					f[i][j] = f[i-1][j-k]+a[i][k];
    					ans[i][j] = k;
    				}      	
    	printf("%d
    ", f[n][m]);
    	print(n,m);
        return 0;
    }
    

    为什么改成小于等于就对了?如果我们在等于时也更新一下ansi j= k;

    就可以保证这个k是最优状态里最大的,也就保证最终得到的方案字典序最小

    还有一种写法,就是倒序枚举i,j,k,这样一开始记录的k值就是最大的

  • 相关阅读:
    mysql 游标使用
    springboot 集成swagger2
    springboot + thymeleaf静态资源访问404
    Win10系列:VC++绘制几何图形1
    Win10系列:VC++媒体播放控制4
    Win10系列:VC++媒体播放控制3
    Win10系列:VC++媒体播放控制2
    Win10系列:VC++媒体播放控制1
    Win10系列:VC++媒体播放
    Win10系列:VC++文件选取
  • 原文地址:https://www.cnblogs.com/hzoi-poozhai/p/12769739.html
Copyright © 2020-2023  润新知