uva 10944 Nuts for nuts..(状压dp)
题意:一幅地图中给出松鼠起点,各坚果的信息,求松鼠收集所有坚果并返回起点的最小步数;
思路:
用二进制数表示坚果的收集状态,0表示未收集,1已收集;mm[i][j]表示节点i和j的相对距离;f[i][j]表示在收集状态为j是收集i的最小步数;
显然,收集每颗坚果的最小步数为f[i][2的(i-1)次方]=mm[0][i];
递增枚举状态值i,状态i中最后被收集的坚果j,枚举i外的坚果k。
f[k][i+1<<(k-1)]=min( f[k][i+1<<(k-1)],f[j][i]+mm[j][k]);
所有坚果收集后,若最后一颗为i,则到i的最小步数为f[i][1<<(n)-1],加上返回起点的步数map[0][i],找到最少步数;
ans=min(f[i][1<<(n)-1]+mm[0][i]);(枚举i)
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define inf (1<<20) #define N 30 #define M 65536 using namespace std; int f[N][M]; char s[N]; int mm[N][N]; int x[N],y[N]; int num,n,m,ans,maxz; int main() { while(scanf("%d%d",&n,&m)!=EOF) { num=0; for(int i=0;i<n;i++) { scanf("%s",s); for(int j=0;j<m;j++) { if(s[j]=='#'){ x[++num]=i; y[num]=j;//坚果位置 } else if(s[j]=='L'){ x[0]=i;y[0]=j;//当前位置 } } } if(!num){ printf("0\n");continue; } for(int i=0;i<=num;i++) for(int j=0;j<=num;j++) mm[i][j]=max(abs(x[i]-x[j]),abs(y[i]-y[j]));//计算节点间相对距离的矩阵 maxz=(1<<num)-1; for(int i=0;i<=maxz;i++){ for(int j=0;j<=num;j++) f[j][i]=inf; } for(int i=1;i<=num;i++) f[i][1<<(i-1)]=mm[0][i];//只收集第i个坚果的步数 for(int i=0;i<maxz;i++) //枚举当前坚果被收集的状态 { for(int j=1;j<=num;j++) if(i&(1<<(j-1)))//枚举最后被收集的坚果j for(int k=1;k<=num;k++) //枚举i状态外的坚果k,调整k被收集的最优步数 if(!(i&(1<<(k-1)))) f[k][i+(1<<(k-1))]=min(f[k][i+(1<<(k-1))],f[j][i]+mm[j][k]); } ans=inf; for(int i=1;i<=num;i++) //枚举最后被收集的坚果(返回‘L’位置的最少步数)i,调整最优步数 ans=min(ans,f[i][maxz]+mm[i][0]); printf("%d\n",ans); } return 0; }
有些梦想现在不去实现,以后就再也没机会了!!