zoukankan      html  css  js  c++  java
  • 洛谷 p2066 机器分配

    这个题是我自己打出来的第二道题~(≧▽≦)/~啦啦啦,虽然想+改好像得有2小时,并且解法很不像正解。

    对于n组数据,我们发现,当前f【m】的一组可能解为w1台+w2台(w1+w2=j),此时我们并不关心w1和w2是怎么来的。

    f【m】的全部解为

    0,1,2,3....m

    m,m-1,m-2......0

    也就是说,我们只需要不停找到一个可控的f【1~m】与一组未知的数继续和出一个新的f【1~m】,直到和完全部的组。这可能就是区间dp的雏形吧。

    下面来证一下它的可行性:

    f【m】的全部解为

    0,1,2,3....m      现最优解   q1

    m,m-1,m-2......0   未求的   q2

    以m-2和2为例,q1中的2为1~求得q1这一组中,所有分配为2的最大值,那么m-2+(q1中的2)>=m-2+其它任意分配为2(1~求得q1这一组中)

    b【第几次合并】【坑位(最大可分配数量)】【组数】用来记录第几组分配了几个

    共合并n-1次,初始f[i]=a[1][i]

    没有被更新的b数组就从上一次中继承,now_i相当于w1是现最优解中的,now_j相当于w2是未知中的。

    但是,还有一个坑点:要求答案的字典序最小

    需要把第二层循环j和第三层循环k全部改为倒序,因为更改now_i值和now_j值时条件为严格大于,所以非字典序的答案即使相同也不会被记录。

    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    int n,m,a[11][16],f[16],b[16][18][16];
    int now_i,now_j;
    
    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<=m;i++){
    		f[i]=a[1][i];
    		b[1][i][1]=i;
    	}	
    	for(int i=2;i<=n;i++){
    		for(int j=m;j>=1;j--){
    			now_i=-2,now_j=-2;
    			for(int k=j;k>=1;k--){
    				if(f[j-k]+a[i][k]>f[j]){
    					now_i=j-k;
    					now_j=k;
    					f[j]=f[j-k]+a[i][k];
    				}
    			}
    			if(now_i==-2&&now_j==-2){
    				for(int k=1;k<=i;k++)
    					b[i][j][k]=b[i-1][j][k];
    			}
    			else{
    				b[i][j][i]=now_j;
    				for(int k=1;k<i;k++)//不要把i也更新进去 
    					b[i][j][k]=b[i-1][now_i][k];
    			}
    		}
    	}
    	printf("%d
    ",f[m]);
    	for(int i=1;i<=n;i++)
    		printf("%d %d
    ",i,b[n][m][i]);
    	return 0;
    }
    

     感谢上帝~

  • 相关阅读:
    操作系统__kali(1)基本操作指令,以及常用工具
    Log4net入门(回滚日志文件篇)
    Log4net入门(日志文件篇)
    Log4net入门(控制台篇)
    openwrt控制GPIO
    openwrt DTS介绍
    openwrt bin文件解析
    STM32(三十)蓝牙通信
    openwrt的led configuration
    uci文件生成脚本函数说明
  • 原文地址:https://www.cnblogs.com/jindui/p/11084791.html
Copyright © 2011-2022 走看看