• P2066 机器分配 (DP+DP输出)


    题目描述

    总公司拥有高效设备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
    分析:dp(i,j)表示前I个公司一共选J台机器的最优答案,那转移方程为dp(i,j)=max(dp(i-1,j-k);这个方程表示如果我们第I选择了J台,那应该是从i-1次中选择K台才得出的答案;
    那么如何输出字典序最小呢?我们可以使用pa(i,j,h) 表示前i个公司一共选j台机器,h号公司选了多少台;
    #include<bits/stdc++.h>
    using namespace std;
    int f[11][16],graph[11][16],path[11][16][11],n,m;
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                cin>>graph[i][j];
        }
        memset(f,0,sizeof(f));
        for(int i=1;i<=n;i++)
            for(int j=0;j<=m;j++)    
                for(int k=0;k<=j;k++)
                {
                    if (f[i][j]<f[i-1][j-k]+graph[i][k])
                    {
                        f[i][j]=f[i-1][j-k]+graph[i][k];
                        for(int h=1;h<i;h++) path[i][j][h]=path[i-1][j-k][h];//path数组只有在状态发生转移时才更新
                        path[i][j][i]=k;
                    }    
                }
        cout<<f[n][m]<<endl;
        for(int i=1;i<=n;i++) cout<<i<<" "<<path[n][m][i]<<endl;
        return 0;
    }

    但是!!!!!!!这并不可以AC 因为还有个限制条件那就是字典序最小,我们怎么解决呢??

    按上面这种方式的枚举,我们都是尽可能的选满填充所以得出的字典序可能是最大的,那我们可以尽可能的不选满,那就是意味着我们要倒叙的枚举

    #include<stdio.h>
    #include<string.h>
    int mo[20][20],dp[20][20],pa[20][20][20];
    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",&mo[i][j]);
        memset(dp,0,sizeof(dp));
        for(int i=1 ; i<=n ; i++)
        {
            for(int j=0 ; j<=m ; j++)
            {
                for(int k=0 ; k<=j ; k++)
                {
                    if(dp[i][j]<dp[i-1][k]+mo[i][j-k])
                    {
                        dp[i][j]=dp[i-1][k]+mo[i][j-k];
                        for(int h=1 ; h<i ; h++)
                        pa[i][j][h]=pa[i-1][k][h];
                        pa[i][j][i]=j-k;
                    }
                }
            }
        }
        printf("%d
    ",dp[n][m]);
        for(int i=1 ; i<=n ; i++)
            printf("%d %d
    ",i,pa[n][m][i]);
        return 0 ;
    }

    这里给的数据很小,如果数据大的话,有个空间优化

    #include <iostream>
    
    using namespace std;
    
    int f[20],n,m,w[20][20],ans[20][20];
    
    int main()
    {
        int i,j,k;
    
        cin>>n>>m;
    
        for (i=1;i<=n;++i)
        {
            for (j=1;j<=m;++j)
            {
                cin>>w[i][j];
            }
        }
    
        for (i=n;i>0;--i)
        {
            for (j=m;j>=0;--j)
            {
                for (k=1;k<=j;++k)
                {
                    if (f[j-k]+w[i][k]>f[j])
                    {
                        f[j]=f[j-k]+w[i][k];
                        ans[i][j]=k;    //保存f(i,j)取最大时k的值
                    }
                }
            }
        }
    
        cout<<f[m];
    
        for (i=1,j=m;i<=n;++i)
        {
            cout<<endl<<i<<" "<<ans[i][j];
            j-=ans[i][j];   //算出最优方案第i+1~n公司共使用了几台机器,也就是f(i,j)是由f(i+1,?)转移过来的
        }
    
        return 0;
    }
  • 相关阅读:
    毕业四年,你赚回四年的花费了吗?
    【转】解决VS2008 开发Windows Mobile 项目生成速度慢的问题
    WinCE/Mobile上下滑动浏览DataGrid数据 【转】
    【转】取得汉字拼音的首字母
    漂亮的 Windows Mobile 按钮
    SQLite中的常用操作(总结)
    浅谈HTTP中Get与Post的区别
    Oracle学习之数组
    firefox与ie 的javascript区别
    常用bash shell 脚本
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9480274.html
Copyright © 2020-2023  润新知