应为看到题目上说是类似于背包问题,有什么代价啊,数量啊,所以可以想到状压 DP , f[s] 表示当前还剩 s 集合的开水瓶的最小代价。
每次用for循环枚举i的开水到j算出代价,然后选取最优的代价实际合并到j上去,代码很短只有50行,代码的精髓就是
f[i^(1<<j)]=min(f[i]+c[j][k],f[i^(1<<j)]);
if(x==m+1)
ans=min(ans,f[i^(1<<j)]);
这三句话就是状压DP
#include<bits/stdc++.h>
using namespace std;
const int maxn=20;
int f[1<<maxn];
int c[maxn][maxn];
int n,m,ans=0x3f3f3f3f;
inline int count(int x)
{
int res=0;
while(x)
{
if(x&1)
res++;
x>>=1;
}
return res;
}
int main()
{
scanf("%d%d",&n,&m);
int maxv=(1<<n)-1;
for(int i=0;i<n;++i)
for(int j=0;j<n;++j)
scanf("%d",&c[i][j]);
memset(f,0x3f,sizeof(f));
f[maxv]=0;
for(int i=maxv;i>=1;--i)
{
int x=count(i);
if(x<2)
continue;
for(int j=0;j<n;++j)
{
if(i&(1<<j))
{
for(int k=0;k<n;++k)
{
if((i&(1<<k))&&j!=k)
{
f[i^(1<<j)]=min(f[i]+c[j][k],f[i^(1<<j)]);
if(x==m+1)
ans=min(ans,f[i^(1<<j)]);
}
}
}
}
}
printf("%d\n",ans);
return 0;
}