• 【解题报告】洛谷P3959 宝藏


    【解题报告】洛谷P3959 宝藏

    原题连接

    https://www.luogu.com.cn/problem/P3959

    思路

    这道题目,本来今天yht老师讲了个大力搜索,什么模拟退火来着,但是最后,还是回归了本源,状态动态规划

    首先我们这么想

    我们每条路肯定只联通一次,然后我们对于可以钦定一个集合S

    用来表示某个点选不选的最小代价

    但我们要进行状态转移,我们要从一个点走到另一个点,然后要用某个节点的深度来计算代价

    所以我们设置(f[x][S][d])来表示点x在S中并且深度为d的时候的最小代价

    因为是从上一个状态走下来的,所以我们要加上这条边

    则状态转移方程为

    [f[x][1<<(x-1)|S][d]=min{sum+dis[y]+g[y][x]} ]

    其中y和x表示上次的点和这次的点,sum表示这次以前的最小代价

    dis数组在dfs的时候顺便处理一下就好了

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #define int long long
    using namespace std;
    const int maxn=15;
    const int INF=1e9;
    int n,m,maxx;
    int g[maxn][maxn];
    int dis[maxn],ans=INF;
    int f[maxn][1<<maxn][maxn];
    inline void dfs(int s,int sum,int dep)
    {
    	if(sum>=ans)
    	return ;
    	if(s==maxx)
    	{
    		ans=sum;
    		return ;
    	}
    	for(int i=1;i<=n;i++)
    	{
    		if(!(1<<(i-1)&s))
    		continue;
    		for(int j=1;j<=n;j++)
    		{
    			if(!(1<<(j-1)&s)&&g[i][j]<INF)
    			{
    				if(f[j][1<<(j-1)|s][dep+1]<=sum+dis[i]*g[i][j])
    				continue;
    				f[j][1<<(j-1)|s][dep+1]=sum+dis[i]*g[i][j];
    				dis[j]=dis[i]+1;
    				dfs(1<<(j-1)|s,f[j][1<<(j-1)|s][dep+1],dep+1);
    			}
    		}
    	}
    }
    signed main()
    {
    	cin>>n>>m;
    	maxx=(1<<n)-1;
    	memset(g,0x3f3f3f,sizeof(g));
    	for(int i=1;i<=m;i++)
    	{
    		int x,y,z;
    		cin>>x>>y>>z;
    		g[x][y]=g[y][x]=min(g[x][y],z);
    	}
    	for(int i=1;i<=n;i++)
    	{
    		memset(dis,0,sizeof(dis));
    		memset(f,0x3f3f3f,sizeof(f));
    		dis[i]=1;
    		dfs(1<<(i-1),0,0);
    	}
    	cout<<ans<<'
    ';
    	return 0;
    }
    
    本博文为wweiyi原创,若想转载请联系作者,qq:2844938982
  • 相关阅读:
    常用shell
    JavaScript基础
    CSS动画-页面特效
    CSS3常用操作
    CSS3的盒子模型
    CSS定位
    JQuery中的DOM操作
    [单词用法总结]-as
    JQuery选择器
    css选择器
  • 原文地址:https://www.cnblogs.com/wweiyi2004/p/15362997.html
Copyright © 2020-2023  润新知