poj 1742 Coins

题目大意:

一个人有若干不同面值、同面值不同数量的硬币。告诉你硬币面值的种类和对应的数量,求用这些硬币能正好凑成多少个小于m的整数。

解题思路:

类似于素数打表,开一个m大的bool数组记录哪些数能被凑出来,外层for循环硬币的种类,对于每种硬币都把m挨个算一遍,时间复杂度为O(n*m=1000w)。在算的时候首先要判断当前的点有没有已经能被凑出来了,如果值得去凑,那么再看j-A[i]那个点是不是已经是1了,如果已经是1了,还要判断之前那个是1的点用了几次当前种类的硬币,要保证当前面值的硬币还没用完,如果条件都满足,那么就可以把当前的点更新了。

感想:

我一开始就想这么做,公式都推出来了,但是脑子短路以为这是个n*m*c=100亿的算法(我sb的想成了对于每个n的每个m点都要把已经置1的点往后挨个+c[i]来更新,忘了可以直接倒着来,如果当前的还没更新再去更新,就是这一个细节啊,看了一眼别人的博客,发现真有这么写的,以为是数据太水过了,仔细看看才发现是自己sb了)。


Sample Input

3 10
1 2 4 2 1 1
2 5
1 4 2 1
0 0

Sample Output

8
4

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <stack>
using namespace std;
typedef long long LL;
const int INF=0x7fffffff;
const int MAX_N=100005;

int n,m;
int A[105];
int C[105];
bool vis[MAX_N];
int num_of_used[MAX_N];

int main(){
    while(scanf("%d%d",&n,&m)&&n!=0){
        for(int i=1;i<=n;i++){
            scanf("%d",&A[i]);
        }
        for(int i=1;i<=n;i++){
            scanf("%d",&C[i]);
        }

        memset(vis,0,sizeof(vis));
        vis[0]=1;
        int ans=0;
        for(int i=1;i<=n;i++){
            memset(num_of_used,0,sizeof(num_of_used));
            for(int j=A[i];j<=m;j++){
                if(!vis[j]&&vis[j-A[i]]&&num_of_used[j-A[i]]<C[i]){
                    vis[j]=1;
                    num_of_used[j]=num_of_used[j-A[i]]+1;
                    ans++;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


你可能感兴趣的:(dp,ACM,poj)