看了网上很多完全背包的题,都感觉没解释清楚。
设包子数为 a1 a2 a3 a4 a5...an
考虑 对于凑一个 x 数
k1 * a1 + k2*a2 +... +kn*an = x
两边mod a1
(k2*a2%a1 +k3*a3%a1 + ... +kn*an%a1 )%a1= x%a1
x%a1 的范围为 [0,a1);
比如说 想凑 x = 31,a1 = 5; x%a1 = 1;
我能通过 (k2*a2%a1 +k3*a3%a1 + ... +kn*an%a1 )%a1 组合能凑出一个1
那么 我只要 将能凑出 1的 (k2*a2%a1 +k3*a3%a1 + ... +kn*an%a1 )%a1组合 再加上5个a[1] , 即可凑出来
但是 有个情况 就是 (k2*a2%a1 +k3*a3%a1 + ... +kn*an%a1 )%a1凑出来的是mod之后的数 可能原这个数为 31 也可能是41 51 . 如果是51的话 那么31肯定是无法组合的
所以我们用最短路求解
d[i] 表示 凑出 x%a[1] =i 所需要的数最小合
建边 就是
mp[j][(j+a[i])%a[0]]=min(mp[j][(j+a[i])%a[0]],a[i]);
比如说 对于 a[1] = 5 a[2]=8 a[2]%a[1]=3
那么 对于 结果余数为1的情况 , 可以通过加一个 a[2] 变成余数为4 所以 1->4有路径,路径费用为a[2] = 8;
这样 一次最短路后 ,
对 i ~ [0,a[1])范围
如果存在 d[i]=inf 那么说明这个点不可达 所以 任意 k*a[1]+i (该数mod a[1] = i) 都不能组合 所以此时结果为inf
如果 d[i] = x 那么 对于任意 x'>x 且 x'%a[1]=i 都可以组合 (x'与x相差整数个a[1],差几倍补几倍就行了)
而 对任意 x'<x 且 x'%a[1]=i 都到达不了 所以 不能到达的数为 x/a[1];
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define maxn 110
using namespace std;
typedef long long ll;
int mp[maxn][maxn];
int d[maxn];
int v[maxn];
int a[maxn];
const int inf = 0x3fffffff;
int main()
{
for(int i = 0 ; i<maxn ; i++){
for(int j = 0 ; j<maxn ; j++){
mp[i][j]=inf;
}
mp[i][i]=0;
}
int n;
scanf("%d",&n);
int minn=0;
for(int i = 0 ; i<n ; i++){
scanf("%d",&a[i]);
}
sort(a,a+n);
for(int i = 0 ; i<n ; i++){
for(int j = 0 ; j<a[0]; j++){
mp[j][(j+a[i])%a[0]]=min(mp[j][(j+a[i])%a[0]],a[i]);
}
}
for(int i = 0 ; i<a[0] ; i++){
d[i]=inf;
}
mp[0][0]=0;
d[0]=0;
for(int i = 0 ; i<a[0] ; i++){
int minn = inf;
int k = 0;
for(int j = 0 ; j<a[0] ; j++){
if(d[j]<minn&&!v[j]){
minn=d[j];
k=j;
}
}
v[k]=1;
for(int j = 0 ; j<a[0] ; j++){
if(d[j]>d[k]+mp[k][j]){
d[j]=d[k]+mp[k][j];
}
}
}
for(int i = 0 ; i<a[0] ; i++){
if(d[i]>=inf){
printf("INF\n");
return 0;
}
}
ll sum = 0;
for(int i = 0 ; i<a[0] ; i++){
sum += d[i]/a[0];
}
printf("%d\n",sum);
return 0;
}
0s ac