zoukankan      html  css  js  c++  java
  • hdu3001(三进制状压)

    题目大意:

    现在给你一个有n个点和m条边的图,每一条边都有一个费用,每个点不能经过超过两次,求所有点至少遍历一次的最小费用

    其中n<=10 m没有明确限制(肯定不会超过1e5)

    一看到这个数据范围,第一想法就是状压QWQ

    但是转念一想,woc,每个点不一定只经过一次咯。

    woc,那不就是三进制状压?!

    好的,至此,这个题成功的成为了我人生中的第一道三进制状压

    f[S][i]表示已经走过的点的集合是S 当前在i的最小费用

    首先,我们要先预处理一个num数组

    num[i][j]表示i这个数的三进制拆分的第j位是什么

    void count()
    {
        for (int i=0;i<=59049;i++)
        {
            int cnt=i;
            for (int j=1;j<=10;j++)
              num[i][j]=cnt%3,cnt/=3;
        }
    }
    

    便于之后的计算

    之后枚举状态

    枚举当前点,枚举目标点,进行转移即可

    上代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    
    using namespace std;
    
    inline int read()
    {
       int x=0,f=1;char ch=getchar();
       while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
       while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
       return x*f;
    }
    
    int f[100010][12];
    int num[100010][12];
    int n,m;
    int a[20][20];
    int ymh;
    bool pp;
    
    int qsm(int i,int j)
    {
        int ans=1;
        while (j)
        {
            if (j&1) ans*=i;
            i=i*i;
            j>>=1;
        }
        return ans;
    }
    
    void init()
    {
        memset(f,127/3,sizeof(f));
        memset(a,-1,sizeof(a));
    }
    
    void count()
    {
        for (int i=0;i<=59049;i++)
        {
            int cnt=i;
            for (int j=1;j<=10;j++)
              num[i][j]=cnt%3,cnt/=3;
        }
    }
    
    int main()
    {
      count();
      while (scanf("%d%d",&n,&m)!=EOF){
          init();
          int ans=1e9;
          pp=true;      
        for (int i=1;i<=m;i++)
          {
              int u,v,w;
              u=read();v=read();w=read();
              if (a[u][v]==-1){
                  a[u][v]=w;
              }
              else a[u][v]=min(a[u][v],w);
              a[v][u]=a[u][v];
          }
          ymh=qsm(3,n)-1;
          //cout<<ymh<<endl;
          for (int i=1;i<=n;i++)
            f[qsm(3,i-1)][i]=0;
          for (int i=1;i<=ymh;i++)
          {
              bool flag=true;
              for (int j=1;j<=n;j++)
              {
                  if (num[i][j]==0)
                  {
                      flag=false;
                      continue;
                  }
                  for (int k=1;k<=n;k++)
                  {
                      if (a[j][k]!=-1 && num[i][k]<2 && k!=j)
                      {
                          int kk=i+qsm(3,k-1);
                          f[kk][k]=min(f[kk][k],f[i][j]+a[j][k]);
                      }
                  }
              }
            if (flag)
              for (int j=1;j<=n;j++)
               ans=min(ans,f[i][j]);
          }
        if (ans==f[100001][11]) ans=-1;
          cout<<ans<<endl;
      }
      return 0;
    }
    
  • 相关阅读:
    序列
    2018131
    成都七中
    NOIP2017
    洛谷P1352 CodeVS1380 没有上司的舞会
    BZOJ1087 SCOI2005 互不侵犯King
    11-4-2017 星期六 R-Day?
    11-3-2017 星期五
    11-2-2017 星期四
    USACO 2014 US Open, Silver Problem 2. Dueling GPSs
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10160616.html
Copyright © 2011-2022 走看看