完全背包

与01背包很相似,只是物品无限次,要正序枚举。

UVA 674

整数划分,用记忆化搜索的话会更快。

 

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=1e4+10;
int dp[maxn],c[5]={1,5,10,25,50},n;

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        for(int i=0;i<5;i++)
        {
            for(int j=c[i];j<=n;j++)
                dp[j]+=dp[j-c[i]];
        }
        cout << dp[n] << endl;
    }
    return 0;
}


记忆化搜索

#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
const int maxn=1e4;
int dp[maxn][5],v[5]={1,5,10,25,50};
 
int dfs(int x,int y)
{
    if(dp[x][y]!=-1)
        return dp[x][y];
    dp[x][y]=0;
    for(int i=y;i<5&&x>=v[i];i++)
        dp[x][y]+=dfs(x-v[i],i);
    return dp[x][y];
}
 
int main()
{
    int n;
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<5;i++)
        dp[0][i]=1;
    while(scanf("%d",&n)!=EOF)
    {
        cout << dfs(n,0) << endl;
    }
    return 0;
}

uva 147

将每个数*100然后进行背包

 

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=3e4+10;
int v[12]={0,5,10,20,50,100,200,500,1000,2000,5000,10000};
ll dp[maxn];

int main()
{
    float n;
    while(scanf("%f",&n)!=EOF)
    {
        if(n==0)
            break;
        int m=(int)(n*100+0.5);
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        for(int i=1;i<=11;i++)
        {
            for(int j=v[i];j<=m;j++)
                dp[j]+=dp[j-v[i]];
        }
        printf("%6.2f%17lld\n",n,dp[m]);
    }
    return 0;
}

POJ 3181

 

开两个long long类型的数组来处理大数

 

#include <iostream>
using namespace std;

typedef long long ll;
const int maxn=1e3+10;
const ll inf=1e17;
ll dp1[maxn],dp2[maxn];
int n,k;

int main()
{
    cin >> n >> k;
    dp1[0]=1;
    for(int i=1;i<=k;i++)
    {
        for(int j=i;j<=n;j++)
        {
            dp2[j]=dp2[j]+dp2[j-i]+(dp1[j]+dp1[j-i])/inf;
            dp1[j]=(dp1[j]+dp1[j-i])%inf;
        }
    }
    if(dp2[n])
        cout << dp2[n];
    cout << dp1[n]  << endl;
    return 0;
}


POJ 1787

记录dp路径

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
#define inf 0x3f3f3f3f
#define PI acos(-1.0)

typedef long long ll;
const int maxn=1e4+10;
int dp[maxn],c[5]={0,1,5,10,25},n,num[5],c1[5],c2[5],p[5][maxn];


int main()
{
    while(scanf("%d%d%d%d%d",&n,&c1[1],&c1[2],&c1[3],&c1[4])!=EOF)
    {
        if(n==0&&c1[1]==0&&c1[2]==0&&c1[3]==0&&c1[4]==0)
            break;
        ll sum=0;
        for(int i=1;i<=4;i++)
            sum+=(c1[i]*c[i]);
        if(sum<n)
        {
            printf("Charlie cannot buy coffee.\n");
            continue;
        }
        for(int i=0;i<=n;i++)
            dp[i]=-inf;
        dp[0]=0;
        memset(c2,0,sizeof(c2));
        memset(p,0,sizeof(p));
        for(int i=1;i<=4;i++)
        {
            for(int j=c[i];j<=n;j++)
            {
                if(dp[j]<dp[j-c[i]]+1)
                {
                    if(c1[i]<p[i][j-c[i]]+1)
                        break;
                    dp[j]=dp[j-c[i]]+1;
                    p[i][j]=p[i][j-c[i]]+1;
                }
            }
        }
        int i=4,j=n;
        sum=0;
        while(i>0&&j>0)
        {
            if(p[i][j]>0)
            {
                sum+=c[i];
                c2[i]++;
                j-=c[i];
            }
            else
                i--;
        }
        if(sum!=n)
            printf("Charlie cannot buy coffee.\n");
        else
            printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",c2[1],c2[2],c2[3],c2[4]);
    }
    return 0;
}


ZOJ 3524

 

将图建出来,从出发点开始往终点进行完全背包

 

#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define PI acos(-1.0)
#define pb(x) push_back(x)

typedef long long ll;
const int maxn=2e3+5;
const int maxm=605;

struct node
{
    int v,l;
};
int dp[maxn][maxn],w[maxm],c[maxn][maxn],tp[maxn],v[maxm],N,W,M,X,min_c,max_v,in[maxm],vis[maxm];
vector<node> a[maxm];

void topo()
{
    memset(tp,0,sizeof(tp));
    stack<int> st;
    for(int i=1;i<=N;i++)
        if(!in[i])
            st.push(i);
    int len=1;
    while(!st.empty())
    {
        int u=st.top();
        st.pop();
        tp[len++]=u;
        for(int i=0;i<a[u].size();i++)
        {
            node e=a[u][i];
            if(!(--in[e.v]))
                st.push(e.v);
        }
    }
}

void complete_pack()
{
    memset(dp,0,sizeof(dp));
    memset(c,-1,sizeof(c));
    memset(vis,0,sizeof(vis));
    for(int i=0;i<=W;i++)
    {
        c[X][i]=0;
        if(i>=w[X])
            dp[X][i]=max(dp[X][i],dp[X][i-w[X]]+v[X]);
    }
    vis[X]=1;
    min_c=0,max_v=dp[X][W];
    for(int i=1;i<=N;i++)
    {
        int u=tp[i];
        if(!vis[u])
            continue;
        for(int j=0;j<a[u].size();j++)
        {
            node e=a[u][j];
            int vv=e.v;
            vis[vv]=1;
            for(int k=0;k<=W;k++)
            {
                if(dp[vv][k]<dp[u][k])
                    dp[vv][k]=dp[u][k],c[vv][k]=c[u][k]+k*e.l;
                else if(dp[vv][k]==dp[u][k])
                {
                    if(c[vv][k]==-1)
                        c[vv][k]=c[u][k]+e.l*k;
                    else
                        c[vv][k]=min(c[vv][k],c[u][k]+k*e.l);
                }
            }
            for(int k=w[vv];k<=W;k++)
            {
                if(dp[vv][k]<dp[vv][k-w[vv]]+v[vv])
                    dp[vv][k]=dp[vv][k-w[vv]]+v[vv],c[vv][k]=c[vv][k-w[vv]];
                else if(dp[vv][k]==dp[vv][k-w[vv]]+v[vv])
                    c[vv][k]=min(c[vv][k],c[vv][k-w[vv]]);
            }
            for(int k=0;k<=W;k++)
            {
                if(dp[vv][k]>max_v||(dp[vv][k]==max_v&&c[vv][k]<min_c))
                   min_c=c[vv][k],max_v=dp[vv][k];
            }
        }
    }
}

int main()
{
    while(scanf("%d%d%d%d",&N,&M,&W,&X)!=EOF)
    {
        for(int i=1;i<=N;i++)
            cin >> w[i] >> v[i];
        memset(in,0,sizeof(in));
        for(int i=0;i<=N;i++)
            a[i].clear();
        for(int i=0;i<M;i++)
        {
            int x,y,w;
            cin >> x >> y >> w;
            node e;
            e.v=y;
            e.l=w;
            a[x].pb(e);
            in[y]++;
        }
        topo();
        complete_pack();
        cout << min_c << endl;
    }
    return 0;
}


ZOJ 3662

 

将全部lcm预处理出来,然后第i个从前i-1的最小和开始进行dp

 

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=1010;
const ll MOD=1e9+7;
int dp[2][maxn][maxn],LCM[maxn][maxn],k,n,m,a[maxn],b[maxn];

int gcd(int x,int y)
{
    return y==0?x:gcd(y,x%y);
}

int lcm(int x,int y)
{
    return x/gcd(x,y)*y;
}

int main()
{
    for(int i=1;i<=1000;i++)
        for(int j=1;j<=1000;j++)
            LCM[i][j]=lcm(i,j);
    while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    {
        int cnt=1;
        for(int i=1;i<=m;i++)
            if(m%i==0)
                a[cnt++]=i;
        memset(b,0,sizeof(b));
        memset(dp[0],0,sizeof(dp[0]));
        dp[0][0][1]=1;
        for(int i=1;i<=k;i++)
        {
            memset(dp[i%2],0,sizeof(dp[i%2]));
            for(int j=i-1;j<=n;j++)
            {
                for(int x=1;x<cnt;x++)
                {
                    if(dp[(i+1)%2][j][a[x]]==0)
                        continue;
                    for(int y=1;y<cnt;y++)
                    {
                        int sum=j+a[y];
                        int l=LCM[a[x]][a[y]];
                        if(sum>n||m%l!=0)
                            continue;
                        dp[i%2][sum][l]=(dp[i%2][sum][l]+dp[(i+1)%2][j][a[x]])%MOD;
                    }
                }
            }
        }
        cout << dp[k%2][n][m] << endl;
    }
    return 0;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值