现在的位置: 首页 > 算法 > 正文

poj 1742 Coins

2019年11月15日 算法 ⁄ 共 2189字 ⁄ 字号 评论关闭

学了种很快的新方法,就是每次填f[j]时直接由f[j-weight[i]]推出,前提是num[j - weight[i]]<used[i]
num每填一行都要清零,num[j]表示当前物品填充j大小的包需要至少使用多少个

PS:单调队列和位运算优化http://www.snowoat.tk/?p=161

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#define CL(a,b) memset(a,b,sizeof(a))
#define MIN(a,b) (a<b?a:b)
#define INF 0x7ffffff
using namespace std;
const int M(100010);
const int N(110);
int f[M],a[N],v[N],used[M];
int main()
{
	int m,n,i,j,k;
	while(scanf("%d%d",&n,&m)!=EOF&&(n+m))
	{
		for(i=0;i<n;i++)
			scanf("%d",&a[i]);
		CL(f,0);
		for(i=0;i<n;i++)
			scanf("%d",&v[i]);
		int t;
	/*	m--;
		sum=MIN(sum,m);
		for(i=0;i<n;i++)
		{
			j=1;
			while(j<=a[i])
			{
				t=j*v[i];
				for(k=sum;k>=t;k--)
					f[k]=MAX(f[k],f[k-t]+t);
				a[i]-=j;
				j<<=1;
			}
			t=a[i]*v[i];
			for(k=sum;k>=t;k--)
				f[k]=MAX(f[k],f[k-t]+t);
		}
		t=0;
		for(i=1;i<=sum;i++)
		{
		//	printf("(%d,%d)",i,f[i]);
			if(f[i]==i)
				t++;
		}*/
		f[0]=1;
		for(i=0;i<n;i++)
		{
			CL(used,0);
			for(j=a[i];j<=m;j++)
			{
				int num=j-a[i];
				if(!f[j]&&f[num]&&used[num]<v[i])
				{
					f[j]=1;used[j]=used[num]+1;
				}
			}
			
		}
		t=0;
		for(i=1;i<=m;i++)
			if(f[i])
				t++;
		printf("%d\n",t);

	}
}

//单调队列优化
#include"iostream"
using namespace std;
int main()
{
    int n,m;
    int A[100],C[100];
    char dp[100010];
    while(scanf("%d%d",&n,&m)&&n!=0&&m!=0)
    {
        for(int i=0;i<n;i++)
		scanf("%d",&A[i]);
        for(int i=0;i<n;i++)
		scanf("%d",&C[i]);
        memset(dp,0,sizeof(dp));
	dp[0]=1;
        for(int i=0;i<n;i++)
        {
            if(A[i]>m)
		continue;
	    if(A[i]*C[i]>=m)
		for(int j=A[i];j<=m;j++)dp[j]=dp[j]|dp[j-A[i]];
	    else
            {
			int t=A[i]*C[i]; 
			for(int j=0;j<A[i];j++)
			{
				int sum=0,x=m-j;
				//用C[i]循环出错,虽然A[i]*C[i]<m但是可能A[i]*C[i]+A[i]-1>=m 
				for(;x>=max(0,m-j-t);x-=A[i]){sum+=dp[x];}
				for(int k=m-j;k>0;k-=A[i])
				{
					sum-=dp[k];dp[k]=sum>0||dp[k];
					if(x>=0){
						sum+=dp[x];x-=A[i];
					}
				}
			}
            }
        }
        int cnt=0;
        for(int i=1;i<=m;i++)
            if(dp[i])cnt++;
        cout<<cnt<<endl;
    }
}

//位运算优化
#include"iostream"
using namespace std;
int main()
{
    int n,m;
    int A[100],C[100];
    char dp[100010];
    while(scanf("%d%d",&n,&m)&&n!=0&&m!=0)
    {
        for(int i=0;i<n;i++)
			scanf("%d",&A[i]);
        for(int i=0;i<n;i++)
			scanf("%d",&C[i]);
        memset(dp,0,m+1);
		dp[0]=1;
        for(int i=0;i<n;i++)
        {
            if(A[i]>m)
				continue;
			if(A[i]*C[i]>=m)
				for(int j=A[i];j<=m;j++)
					dp[j]=dp[j]|dp[j-A[i]];
			else
            {
                int k=0,temp;
                while((1<<k)<C[i])
                {
                    temp=A[i]<<k;
                    for(int j=m;j>=temp;j--)
						dp[j]=dp[j]|dp[j-temp];
                    C[i]-=(1<<k);
                    k++;
                }
                temp=C[i]*A[i];
                for(int j=m;j>=temp;j--)
					dp[j]=dp[j]|dp[j-temp];
            }
        }
        int cnt=0;
        for(int i=1;i<=m;i++)
            if(dp[i])cnt++;
        cout<<cnt<<endl;
    }
}

抱歉!评论已关闭.