与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;
}