首页 > 其他分享 >状压dp 例题

状压dp 例题

时间:2024-05-25 10:25:46浏览次数:20  
标签:状态 int 状压 01001101 77 经过 例题 节点 dp

终于在洛谷上发布题解了QWQ

P10447 最短 Hamilton 路径 题解

分析题目:

一张 n n n 个点的带权无向图,求起点 0 0 0 至终点 n − 1 n-1 n−1 的最短 Hamilton 路径(从 0 ∼ n − 1 0\sim n-1 0∼n−1 不重复地经过每个点一次)。

初看题目,不难发现这道题是一个状态压缩 dp 的模板题。

状态压缩简介:

状态压缩,字面意思就是把复杂的状态转化成简洁的二进制来表示,可减少时间与空间复杂度。

打个比方,二进制数 01001101 01001101 01001101 表示的意思为:

0 0 0( 0 0 0 号节点没有被经过) 1 1 1( 1 1 1 号节点已被经过) 00 00 00( 2 , 3 2,3 2,3 号节点未经过) 11 11 11( 4 , 5 4,5 4,5 号节点经过) 0 0 0( 6 6 6 号节点没经过) 1 1 1( 7 7 7 号节点已经过)。

而 ( 01001101 ) 2 = ( 77 ) 10 (01001101)_2=(77)_{10} (01001101)2​=(77)10​,我们只需操作 77 77 77 次即可,简洁明了。

分析题目样例:

5
0 2 4 5 1
2 0 6 5 3
4 6 0 8 3
5 5 8 0 5
1 3 3 5 0

可作图如下:

好啦,分析题目,我们不难想出定义一个 f f f 数组, f i , j f_{i,j} fi,j​ 表示在 i i i 的状态下(上文已提到)最后经过的节点 j j j 所得的最短 Hamilton 路径。

定义:

int f[MAXM][MAXN];

那么我们该如何进行状态转移呢?

我们可以用三层循环来实现:

for(int i=1;i<(1<<n);i++)//枚举状态
	{
		for(int j=0;j<n;j++)//枚举每个点
		{
			if(!((i>>j)&1)) continue;//如果点j已经被经历过,就跳过它
			for(int k=0;k<n;k++)//这里比较难想,意思是在i的状态下已被经过的点的个数
				if(((i^(1<<j))>>k)&1)
					f[i][j]=min(f[i][j],f[i^(1<<j)][k]+a[k][j]);//状态转移方程,要么是本身,要么则为以i^(1<<j)为状态的节点k到j,有点类似最短路的floyd
		}
	}

最后我们的答案就是 f 2 n − 1 , n − 1 f_{2^{n}-1 , n-1} f2n−1,n−1​。

即在状态为 2 n − 1 2^{n}-1 2n−1(全被经过了)下的 n − 1 n-1 n−1 号节点。

AC Code:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=25,MAXM=(1<<20),inf=0x3f;//定义变量,inf为无限
int n,a[MAXN][MAXN],f[MAXM][MAXN];
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			scanf("%d",&a[i][j]);
   	//输入无需多嘴
	memset(f,inf,sizeof(f));//一开始f数组都是无限的
	f[1][0]=0;//还没开始旅程,为0
	for(int i=1;i<(1<<n);i++)//枚举状态
	{
		for(int j=0;j<n;j++)//枚举每个点
		{
			if(!((i>>j)&1)) continue;//经过了
			for(int k=0;k<n;k++)//上一次经过了哪些点?
				if(((i^(1<<j))>>k)&1)//枚举从上一个经过的节点走到j节点
					f[i][j]=min(f[i][j],f[i^(1<<j)][k]+a[k][j]);//状态转移
		}
	}
	printf("%d\n",f[(1<<n)-1][n-1]);//out
	return 0;
    //完结撒花
}

AC 记录

标签:状态,int,状压,01001101,77,经过,例题,节点,dp
From: https://blog.csdn.net/Brilliant_Sky/article/details/139193618

相关文章

  • Python案例题目,入门小白题
    1.抓取链家前十页的数据链家网址:长沙房产网_长沙房地产_长沙房产门户(长沙链家网)1.1.计算均价和总价importtime​fromseleniumimportwebdriverfromselenium.webdriver.common.byimportBy​driver=webdriver.Chrome()driver.get("https://cs.lianjia.com/zu......
  • dp商品缓存
    缓存更新策略缓存更新是redis为了节约内存而设计出来的一个东西,主要是因为内存数据宝贵,当我们向redis插入太多数据,此时就可能会导致缓存中的数据过多,所以redis会对部分数据进行更新,或者把他叫为淘汰更合适。内存淘汰:redis自动进行,当redis内存达到咱们设定的max-memery的时......
  • hmdp-短信验证
    基于Session实现登录流程发送验证码:用户在提交手机号后,会校验手机号是否合法,如果不合法,则要求用户重新输入手机号如果手机号合法,后台此时生成对应的验证码,同时将验证码进行保存,然后再通过短信的方式将验证码发送给用户短信验证码登录、注册:用户将验证码和手机号进行输入,后......
  • 【教程】WordPress资源下载主题 Modown 书面使用教程
    这篇文章介绍了WordPress资源下载主题Modown的书面使用教程。文章包括安装主题、设置主题选项、自定义分类法、菜单、登录页面、小工具等。使用Modown主题可以通过设置首页模板一和使用mocat短代码来显示分类模块。同时还介绍了如何设置标题模块和显示广告。安装将从模板兔......
  • Java并发编程之newFixedThreadPool线程池
    随着计算机硬件性能的不断提升,多核CPU的普及,现代计算机系统的性能越来越强大。在这样的环境下,如何更好地利用计算机系统的性能优势,提高程序的运行效率,是每一个Java开发者需要思考的问题。Java中提供了多线程编程的支持,但是在多线程编程中,线程的创建、启动、调度等都需要耗费一定的......
  • diffusion model(一):DDPM技术小结 (denoising diffusion probabilistic)
    发布日期:2023/05/18主页地址:http://myhz0606.com/article/ddpm1从直觉上理解DDPM在详细推到公式之前,我们先从直觉上理解一下什么是扩散对于常规的生成模型,如GAN,VAE,它直接从噪声数据生成图像,我们不妨记噪声数据为\(z\),其生成的图片为\(x\)对于常规的生成模型:学习一个解码函......
  • dpkg和rpm对比及常用命令
    dpkg(DebianPackage)和rpm(RPMPackageManager)是两种不同的Linux包管理工具,它们各自在特定的Linux发行版中占据核心地位。两者之间对比如下:所属发行版:dpkg主要用于Debian及其衍生系统,如Ubuntu、Knoppix等。而rpm则主要用于RedHat及其衍生系统,如CentOS和Fedora。软件包格式:d......
  • 线段(线性dp)
     题目链接:https://www.luogu.com.cn/problem/P3842思路:f[i][0]表示走完第i行且停在第i行的左端点最少用的步数f[i][1]同理,停在右端点的最少步数。那么转移就很简单了,走完当前行且停到左端点,那么一定是从右端点过来的,那么从上一行左端点转移的话就是f[i][0]=abs(上一行左端......
  • 背包dp
    P1064[NOIP2006提高组]金明的预算方案思路:有依赖的背包。主要的问题和解决方案,见代码注释.#include<bits/stdc++.h>usingnamespacestd;#defineintlonglong#defineendl"\n"constintN=2e5+10;typedefstructnode{intp,w,typ;}node;boolcmp(nodea,n......
  • Dplayer播放m3u8
    <!--引入DPlayer--><linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.css"><scriptsrc="https://cdn.jsdelivr.net/npm/hls.js/dist/hls.min.js"></script><scriptsrc=&quo......