zoukankan      html  css  js  c++  java
  • NOIP2017 Day2 T2 宝藏(状压DP)

      $O(n*3^n)$好难想...还有好多没见过的操作

      令$f[i][j]$表示最深深度为i,点的状态为j的最小代价,每次枚举状态$S$后,计算$S$的补集里的每个点与S里的点的最小连边代价,再$O(3^n)$枚举S补集的子集,$g[x]$表示补集里状态为x的点往S集合里的点连边的最小代价,然后转移的时候加上它就好。

      但是$g[x]$怎么处理呢...处理不好就会变成$O(3^n*n^2)$了,当然也可以预处理,但是有更简单的方法。因为我们枚举补集的时候是按顺序的,当前状态去掉最低位的状态一定是算过了的,于是就可以用减去lowbit的$g[x-lowbit(x)]$加上最低位往S的某个点连边的最小代价来得到。

      学习到的一些技巧是枚举状态之后每次减去lowbit得到所有的点效率可以提高一些,用于卡常,还有就是上方的$O(n^3)$就能预处理出$g[x]$的方法,都好喵喵啊~

    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    const int maxn=13, inf=6e6;
    int n, m, x, y, z;
    int mp[maxn][maxn], f[maxn][1<<12], g[1<<12], h[1<<12], Log[1<<12], a[maxn], mncost[maxn];
    inline void read(int &k)
    {
        int f=1; k=0; char c=getchar();
        while(c<'0' || c>'9') c=='-' && (f=-1), c=getchar();
        while(c<='9' && c>='0') k=k*10+c-'0', c=getchar();
        k*=f;
    }
    inline int min(int a, int b){return a<b?a:b;}
    int main()
    {
        read(n); read(m); memset(mp, 32, sizeof(mp));
        for(int i=1;i<=m;i++) read(x), read(y), read(z), mp[x][y]=mp[y][x]=min(mp[x][y], z);
        for(int i=0;i<n;i++) Log[1<<i]=i+1;
        memset(f, 32, sizeof(f));
        for(int i=1;i<=n;i++) f[1][1<<(i-1)]=0;
        int st=(1<<n)-1, ans=inf;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=st;j++)
            {
                int cnt=0;
                for(int k=st-j;k;k-=k&-k)
                {
                    int x=Log[k&-k]; a[++cnt]=x; mncost[x]=inf;
                    for(int l=j;l;l-=l&-l) mncost[x]=min(mncost[x], min(1ll*inf, 1ll*mp[Log[l&-l]][x]*(i-1)));
                }
                for(int k=0;k<(1<<cnt);k++)
                {
                    g[k]=g[k-(k&-k)]+mncost[a[Log[k&-k]]];
                    h[k]=k?h[k-(k&-k)]|(1<<(a[Log[k&-k]]-1)):0;
                    f[i][j|h[k]]=min(f[i][j|h[k]], f[i-1][j]+g[k]);
                }
            }
            ans=min(ans, f[i][st]);
        }
        printf("%d
    ", ans);
        return 0;
    }
    View Code

      

  • 相关阅读:
    本来一行可以代替的树节点搜索
    mssql 重新开始标识
    TabContainer实现服务器端回传
    CSS中图片路径的问题
    Javascript在IE下设置innerHTML时出现"未知的运行时错误"
    sql union和union all的用法及效率
    关于动态添加TabPanel遇到的问题以及思考
    关于linq to sql调用存储过程,出现"无法枚举查询结果多次"的问题
    SQL Server 2005连接服务器时的26号错误解决!
    SQL 2000和2005 获取两表的差集
  • 原文地址:https://www.cnblogs.com/Sakits/p/8059670.html
Copyright © 2011-2022 走看看