洛谷 P3959 NOIP2017 宝藏 —— 状压搜索

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

搜索;

不是记忆化,而是剪枝;

邻接矩阵存边即可,因为显然没有那么多边。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll const inf=0x3f3f3f3f3f3f3f3f;
int n,m,S,sid[20][20];
ll s[1<<13],ans,dis[20];
ll dfs(int p,ll w)
{
    if(w>=ans)return inf;
    if(p==S)return w;
//    if(s[p])return s[p];//错误记忆化 
    s[p]=min(s[p],w);//
    ll ret=inf;
    for(int x=1;x<=n;x++)
    {
        if((p&(1<<(x-1)))==0)continue;
        for(int u=1;u<=n;u++)    if(sid[x][u]!=inf&&((1<<(u-1))&p)==0)
        {
            int np=(p|(1<<(u-1)));
            if(s[np]<=w+sid[x][u]*(dis[x]+1))continue;//最优性剪枝 
            dis[u]=dis[x]+1;
            ret=min(ret,dfs(np,w+sid[x][u]*dis[u]));
            dis[u]=0;
        }
    }
    return ret;
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(sid,0x3f,sizeof sid);
    for(int i=1,x,y,z;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        sid[x][y]=min(sid[x][y],z);
        sid[y][x]=sid[x][y];
    }
    ans=inf; S=(1<<n)-1;
    for(int i=1;i<=n;i++)
    {
        memset(s,0x3f,sizeof s);
        ans=min(ans,dfs(1<<(i-1),0));
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-07-27 09:47  Zinn  阅读(320)  评论(0编辑  收藏  举报