ACM天梯赛 L3-001. 凑零钱

题目链接:https://www.patest.cn/contests/gplt/L3-001

*这道题许多大佬用DFS做出来了,Orz!

*为了得到最小序列,不妨按升序排序,且删除值大于m的硬币!

*做法: F[i][j] =1定义: 必须拿第i块硬币,后面的硬币随便你取,能组合j元!不能即为0!

             G[i][j] =1定义: 可拿或不拿第i块硬币,后面的硬币随便你取,能组合j元!不能即为0!

 *j<=100,i<=1e4,内存O(1e6);

*如果G[0][m]==0,表明所有硬币无论怎么取,不能组合m元!"No Solution"!

 G[0][m]==1,绝对有解!

 *后面我们仅需要dfs出最小序列了,dfs(rt,x)作用:遍历[rt,temp)出组合成x元的最小序列;

   函数内考虑两个选择: 能取rt,即F[rt][x]==1,它绝对是当前最小序列的首元素!dfs(rt+1,x-a[rt])!

                                      不能取rt,即F[rt][x]==0,那跳过,继续dfs(rt+1,x)!


#include <iostream>
#include <stdio.h>
#include <algorithm>

using namespace std;

int F[10010][105]={0};// Fij即一定要拿第i块硬币,其它后面硬币随便拿能够组成j元
int G[10010][105]={0};// Gij即可不拿第i块硬币,其它后面硬币随便拿能够组成i元
//F[i][j]=G[i+1][j-a[i]]
//G[i][j]=G[i+1][j]|F[i][j]
int a[10010];

int first=1;
void dfs(int rt,int m){
    if(m==0)return;
    if(F[rt][m]){
        if(first){first=0;}
        else printf(" ");
        printf("%d",a[rt]);
        dfs(rt+1,m-a[rt]);
        return ;
    }
    dfs(rt+1,m);

}
int main(){
    int N,M;
    scanf("%d%d",&N,&M);
    int temp=0;
    while(N--){
        int b;
        scanf("%d",&b);
        if(b<=M)a[temp++]=b;
    }

    sort(a,a+temp);
    for(int i=0;i<=temp;++i)
        G[i][0]=1;
    for(int i=temp-1;i>=0;--i){
        for(int j=0;j+a[i]<=M;++j)
            F[i][j+a[i]]=G[i+1][j];
        for(int j=1;j<=M;++j)
            G[i][j]=G[i+1][j]|F[i][j];
    }

    if(G[0][M]==0)printf("No Solution");
    else dfs(0,M);

    printf("\n");
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值