P2066 机器分配 解析

小日记:
1、今天新学的字体颜色,尽管不熟悉,但玩的666,卡星(开心)

╰( ̄▽ ̄)╮╰( ̄▽ ̄)╮╰( ̄▽ ̄)╮╰( ̄▽ ̄)╮╰( ̄▽ ̄)╮╰( ̄▽ ̄)╮

2、今天油腔滑调,谅解亿下

P2066 机器分配

题目

总公司拥有高效设备\(M\)台,准备分给下属的\(N\)个分公司。各分公司若获得这些设备,可以为国家提供一定的盈利。问:如何分配这\(M\)台设备才能使国家得到的盈利最大?

求出最大盈利值。其中\(M≤15,N≤10\)
分配原则:每个公司有权获得任意数目的设备,但总台数不超过设备数M。

输入

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

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

输出

第1行为最大盈利值

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

\(P.S.\) 要求答案的字典序最小(为后文埋下伏笔)

样例

解析

\(f[i][j]\)为前\(i\)个公司总共分配\(j\)台机器的最大利润。对于第\(i\)家子公司,我们可以给其分配的机器台数为:\(1-m\)

所以在该区间内枚举一个值k,状态转移方程即为:

\(f[i][j]=max(f[i-1][j-k],f[i][j])\)

那么,如何处理方案输出问题呢?

我们设\(path[i][j][h]\)对于前i个公司共分配\(j\)台机器的最优方案,第\(h\)个公司应分配多少台机器,当状态发生转移时,更新\(path\)数组即可。最终的答案就存放在\(path[n][m][i]\)之中。

代码如下

#include <bits/stdc++.h>
using namespace std;
int a[25][25];
int f[25][25];
int path[25][25][25];
int n,m;
int main(){
	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];
					for (int l=1;l<i;l++)
						path[i][j][l]=path[i-1][j-k][l];
					path[i][j][i]=k;	
				}
			}
	printf("%d\n",f[n][m]);
	for (int i=1;i<=n;i++)printf("%d %d\n",i,path[n][m][i]);
	return 0;
}

巴特(But),you only have 90 分的好成绩

Why???

回到题面,我们会发现小小的一行字,人畜无害的鸭子(样子)

     >(' )
       )/
      /(                         <---鸭子
     /  `----/ 
     \  ~=- /——:

要求答案的字典序最小

顿时,我***********

辣么,如何使字典序最小呢?这需要我们倒着枚举。

方程式表示的意思为“不给”第i家公司k台机器(k的值域同上)
注意:并不是\(f\)的意思

那么状态转移方程需改为:

f[i][j]=max(f[i][k],f[i-1][k]+graph[i][j-k]);

再根据这个,对于path数组的更新操作进行一些微调,即可得到满分程序了:

#include <bits/stdc++.h>
using namespace std;
int a[25][25];
int f[25][25];
int path[25][25][25];
int n,m;
int main(){
	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][k]+a[i][j-k]){
					f[i][j]=f[i-1][k]+a[i][j-k];
					for (int l=1;l<i;l++)
						path[i][j][l]=path[i-1][k][l];
					path[i][j][i]=j-k;
				}
			}
	printf("%d\n",f[n][m]);
	for (int i=1;i<=n;i++)printf("%d %d\n",i,path[n][m][i]);
	return 0;
}

posted @ 2021-10-10 20:07  hewt  阅读(95)  评论(0编辑  收藏  举报