状压dp-----三进制

三进制的状压dp要先预处理3^n以及每一个数的每一位

例题

hdu3001

题意:

给定n 个城市已经 m 条路 以及对应路费 c,要求遍历所有城市最少的路费,每个城市不能超过2次。

题解:

看代码吧。。

代码:

 

#include <bits/stdc++.h>
using namespace std;
int n,m,minn;
int load[12][12];
int bit[12];
int dp[60000][12];
int num[60000][12];
#define INF 1e8
int main()
{
  freopen("noip.in","r",stdin);
  freopen("noip.out","w",stdout);
      std::ios::sync_with_stdio(false);
      bit[0]=1;
      for (int i=1;i<=11;i++)
        bit[i]=bit[i-1]*3;
      for (int i=0;i<bit[10];i++)
      {
          int b=i;
          for (int j=0;j<10;j++)
          {
            num[i][j]=b%3;
            b/=3;
          }
      }
      while (cin>>n>>m)
      {
        memset(load,-1,sizeof(load));
        for (int i=0;i<m;i++)
        {
          int a,b,c;
          cin>>a>>b>>c;
          a--;b--;
          if (load[a][b]==-1)
            load[a][b]=load[b][a]=c;
          else 
            load[a][b]=load[b][a]=min(load[a][b],c);
        }
        memset(dp,-1,sizeof(dp));
        int flag,next;        for(int j = 0; j < n; j++)  
            dp[ bit[j] ][j] = 0;
        minn=INF;
        for(int i=0;i<bit[n];i++)
        {
          flag=1;
          for (int j=0;j<n;j++)
          {
             if (num[i][j]==0) flag=0;
             if (dp[i][j]==-1) continue;
             for (int k=0;k<n;k++)
             {
               if (j==k||num[i][k]==2||load[k][j]==-1)
                 continue;
               next=i+bit[k];
               if (dp[next][k]==-1)
                 dp[next][k]=dp[i][j]+load[j][k];
              else dp[next][k]=min(dp[next][k],dp[i][j]+load[j][k]); 
             }
          }
          if (flag==1)
          {
            for (int j=0;j<n;j++)
              if (dp[i][j]!=-1)
                minn=min(minn,dp[i][j]);
          }
        }
      
              if(minn == INF)  
            minn = -1;  
        printf("%d\n", minn);
      }
      return 0;
} 

 

posted @ 2018-03-10 07:50  尹吴潇  阅读(266)  评论(0编辑  收藏  举报