zoukankan      html  css  js  c++  java
  • 洛谷 3959 宝藏——枚举+状压dp

    题目:https://www.luogu.org/problemnew/show/P3959

    原来写了个不枚举起点的状压dp。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N=15,M=(1<<12)+5,INF=0x3f3f3f3f;
    int n,m,lm,b[N][N],dis[M][N];
    ll dp[M];
    int main()
    {
        scanf("%d%d",&n,&m);lm=(1<<n);
        memset(b,0x3f,sizeof b);
        int x,y,z;
        while(m--)
        {
            scanf("%d%d%d",&x,&y,&z);
            b[x][y]=min(b[x][y],z);b[y][x]=b[x][y];
        }
        memset(dp,0x3f,sizeof dp);dp[0]=0;
        for(int i=1;i<=n;i++)dp[1<<(i-1)]=0,dis[1<<(i-1)][i]=1;
        for(int s=1;s<lm;s++)
            for(int i=1;i<=n;i++) if((s&(1<<(i-1)))==0)
            {
                int d=(s|(1<<(i-1)));
                for(int j=1;j<=n;j++) if(s&(1<<(j-1)))
                    if(dp[s]+(ll)b[i][j]*dis[s][j]<dp[d])//b可能是0x3f3f3f 
                    {
                        dp[d]=dp[s]+(ll)b[i][j]*dis[s][j];
                        memcpy(dis[d],dis[s],sizeof dis[s]);
                        dis[d][i]=dis[s][j]+1;
                    }
            }
        printf("%lld
    ",dp[lm-1]);
        return 0;
    }
    View Code

    但其错误是不能改dis。没有最优子结构的性质。

    然后看了题解,发现如果枚举起点,就行了。

    其实和原来想的差不多,但原来的不同起点的dis最后会混到一起,进而少遍历一些状态。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N=15,M=(1<<12)+5,INF=0x3f3f3f3f;
    int n,m,lm,b[N][N],dis[N];
    ll dp[M],ans=INF;
    void dfs(int S)
    {
        for(int i=1;i<=n;i++) if((S&(1<<(i-1)))==0)
        {
            int D=(S|(1<<(i-1)));
            for(int j=1;j<=n;j++) if(S&(1<<(j-1))&&b[i][j]<INF)
                if(dp[S]+b[i][j]*dis[j]<dp[D])
                {
                    dp[D]=dp[S]+b[i][j]*dis[j];
                    dis[i]=dis[j]+1;
                    dfs(D);
                    dis[i]=0;
                }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);lm=(1<<n);
        memset(b,0x3f,sizeof b);
        int x,y,z;
        while(m--)
        {
            scanf("%d%d%d",&x,&y,&z);
            b[x][y]=min(b[x][y],z);b[y][x]=b[x][y];
        }
        for(int i=1;i<=n;i++)
        {
            memset(dp,0x3f,sizeof dp);dp[1<<(i-1)]=0;
            memset(dis,0x3f,sizeof dis);dis[i]=1;
            dfs(1<<(i-1));
            ans=min(ans,dp[lm-1]);
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    POJ_1523 SPF (Tarjan 求割点)
    POJ 3177&& 3352
    POJ 基础数据结构
    Bellman Ford, SPFA 学习笔记(含有负权的单源最短路径)
    HDU_3062 Party (2SAT)
    POJ二分图最大匹配的简单题目
    POJ 2553 The Bottom of a Graph (Trajan 强连通分量 缩点)
    POJ_3678 Katu Puzzle (2SAT)
    HDU_3836 Equivalent Set (Trajan 强连通分量 缩点)
    POJ1904 King's Quest(Tarjan 求缩点)
  • 原文地址:https://www.cnblogs.com/Narh/p/9375668.html
Copyright © 2011-2022 走看看