zoukankan      html  css  js  c++  java
  • UVA 10306 e-Coins(全然背包: 二维限制条件)

    UVA 10306 e-Coins(全然背包: 二维限制条件)

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1247

    题意:

           对于每一个例子。先给定两个数n,m,分别表示有n种硬币,对于每一种硬币有两个价值。分别记做x,y,题目要求从中选择一些硬币,使得满足m*m=X*X+Y*Y, 当中X是选出的硬币的全部x价值的和。Y是全部选出的硬币的y价值的和。硬币有无数多个。如今要求的是,满足上述要求使用的最少的硬币数

    分析:

           硬币数量无限,这就是显然的全然背包问题. 做这类问题首先要搞清楚什么是限制条件, 什么是目标条件?

           本题的限制条件是:  x价值与y价值.(它们值共同构成了限制值m)

           本题的目标条件是: 使得所选硬币最少.

           一般的全然背包状态设计都是用 dp[i][j]==x 表示当决策完前i个物品后, 限制条件正好==j时(或者不超过j), 能得到的目标条件最优(可能要求最小或最大).

           本来我是想用m作为j这维度的限制条件的,可是发现假设用m作为一维限制条件,那么你无法依据当前的m值和你当前选的物品来推出你上一次决策前的m’值. 所以本题须要用x和y两维限制条件来做. (事实上就是加了个维度,没什么本质的变化)

           状态设计: dp[k][i][j]==num 表示决策完前k种硬币后, 当前全部硬币的x价值和为i , 当前全部硬币的y价值和为j 时所须要的最少硬币数目为num.(x价值和 y价值和我们确定唯一的 m )

           状态转移:

           dp[k][i][j] = min( dp[k-1][i][j] , dp[k][i-x[k]][j-y[k]])

           怎样理解上述的状态转移方程呢?

           首先来看dp[k][i][j], 它表示用前k中硬币构成 x价值和为i , y价值和为j 的方法数目. 那么:

           1. 假设我们根本不用第k种硬币(仅仅用前k-1种硬币就可以),我们能够知道有dp[k-1][i][j]种方式能够(不用不论什么一个第k种硬币)构成x价值和为i , y价值和为j 的状态.

           2. 假设我们至少用1个第k种硬币来构成目标状态, 那么我们能够知道有dp[k][i-x[k]][j-y[k]] 种方法能达成目的.

           综上所述, dp[k][i][j] = min( dp[k-1][i][j] ,dp[k][i-x[k]][j-y[k]] )

           初值为dp[0][0][0]=0 , 其它为INF(无穷大).

           终于我们所求为 全部的dp[n][i][j]中满足 i*i+j*j==m*m 的最小值.

           程序实现用的滚动数组, 所以dp仅仅有[i][j]这两个维度.

    AC代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define INF 1e8
    const int maxn=300+5;
    
    int n,m;//n为货币种数,m为须要达到的价值
    int x[maxn],y[maxn];//相应每种货币的两个属性值
    int dp[maxn][maxn];
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            //读输入+初始化
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
                scanf("%d%d",&x[i],&y[i]);
            for(int i=0;i<maxn;i++)
                for(int j=0;j<maxn;j++)
                    dp[i][j]=INF;
            dp[0][0]=0;
    
            //递推求解
            int ans=INF;
            for(int k=1;k<=n;k++)
            for(int i=x[k];i<maxn;i++)
            for(int j=y[k];j<maxn;j++)
            {
                dp[i][j] = min(dp[i][j], dp[i-x[k]][j-y[k]]+1);
                if(i*i+j*j==m*m) //这里假设加了 k==n 就WA 想想为什么?

    ans=min(ans, dp[i][j]); } //输出 if(ans==INF) printf("not possible "); else printf("%d ",ans); } return 0; }


  • 相关阅读:
    查询数据库表的列字段、字段类型、字段长度、是否为空
    AndroidManifest.xml配置文件详解(转载)
    SQL Server Profiler(转载)
    sql 临时表
    sql 全局查询
    react.js
    middleware
    el
    jade模板使用心得
    jade template
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/7071646.html
Copyright © 2011-2022 走看看