洛谷 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\n",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\n",ans);
    return 0;
}

 

posted on 2018-07-27 09:26  Narh  阅读(188)  评论(0编辑  收藏  举报

导航