吃奶酪

· · 题解

博客阅读效果更佳

P1433吃奶酪题解

做法

  1. 状压dp(本篇重点)
  2. 暴搜+最优化剪枝(待实现)
  3. 玄学算法(见其他题解)

前置

      int main()
      {
          scanf("%d\n",&n);
          for(ri i=1;i<=(1<<n);i++)f[i]=inf+1;
          for(ri i=1;i<=n;i++){
              scanf("%lf%lf",&x[i],&y[i]);
              f[(1<<(i-1))]=jl(0,0,x[i],y[i]);//边界  
          }
          for(ri i=1;i<n;i++){
              for(ri j=i+1;j<=n;j++)
              len[i][j]=len[j][i]=jl(x[i],y[i],x[j],y[j]);
          }
          f[0]=0;
          for(ri s=1;s<(1<<n);s++){
              if(f[s]>=inf)continue;
              cnt=0;
              for(ri k=0;k<n;k++){//找到s中所有已经到达的点 ,并存起来 
                  if(((1<<k)&s)!=0){
                      que[++cnt]=k+1;
                  }
              }
              for(ri k=0;k<n;k++){
                  if(((1<<k)&s)==0){//找到s中所有未到的点 
                      tmp=inf;
                      for(ri l=1;l<=cnt;l++){
                          tmp=min(tmp,len[que[l]][k+1]);//找一条由s中的点到新点的最短路 
                      }
                      f[(1<<k)|s]=min(f[(1<<k)|s],f[s]+tmp);
                  }
              }
          }
          printf("%.2lf",f[(1<<n)-1]);
          return 0;
      }
      #include <bits/stdc++.h>
      #define ri register int
      using namespace std;

      int i,j,k,n,que[17],cnt,p;
      double x[17],y[17];
      double tmp,ans;
      double len[17][17],f[17][100000];

      double jl(double x1,double y1,double x2,double y2)
      {
          return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
      }
      int dect(int dec){// 十进制转二进制,便于调试 
          int result = 0,temp = dec,j = 1;
          while(temp){
              result = result + j*(temp%2);
              temp = temp/2;
              j = j*10;
          }
          return result;
      }

      int main()
      {
          memset(f,127,sizeof(f));//double无穷大赋值方式 
          scanf("%d\n",&n);
          for(ri i=1;i<=n;i++){
              scanf("%lf%lf",&x[i],&y[i]);//注意是实数读入 
              f[i][(1<<(i-1))]=jl(0,0,x[i],y[i]);//边界条件 
          }
          for(ri i=1;i<n;i++){
              for(ri j=i+1;j<=n;j++)
              len[i][j]=len[j][i]=jl(x[i],y[i],x[j],y[j]);
          }
          for(ri s=1;s<(1<<n);s++){
              cnt=0;
              for(ri k=0;k<n;k++){//注意从0开始,所以下面的转移方程中要加一 
                  if(((1<<k)&s)==0)que[++cnt]=k;
              }//求出所有未到达的点 
              for(ri i=1;i<=n;i++){
                  if(abs(f[i][s]-f[0][0])<0.0000001) continue;//浮点数相等表示法 
                  for(ri l=1;l<=cnt;l++){
                      f[que[l]+1][s|1<<(que[l])]=min(f[que[l]+1][s|1<<(que[l])],f[i][s]+len[que[l]+1][i]);
                  }
              } 
          }
          ans=f[0][0];//赋予一个无穷大初值 
          for(ri i=1;i<=n;i++)ans=min(ans,f[i][(1<<n)-1]);
          printf("%.2lf",ans);
          return 0;
      }

小细节

最后宣传一波博客,虽然目前什么都没有