zoukankan      html  css  js  c++  java
  • HDU3001 状态压缩DP+三进制

    题意描述

    原题链接

    n个城市,m条路,每个城市最多经过2次,遍历所有城市最小的费用是多少

    如果没有则输出-1

    输入是多组数据

    (n le 10)

    算法解析

    首先我们观察数据范围,不难得出应该是状态压缩DP。

    于是第一眼就该是

    f[i]表示当前已经访问的城市节点们

    问题是当前城市访问次数需要统计

    于是放弃二进制,来存储这个城市是否访问过

    而是,采用三进制,表示这个城市的访问次数,0为未访问

    然后需要知道当前位于的城市

    所以f[i][j]表示状态为i,当前所在城市为j

    那么我们就可以通过当前节点,拓展到其他节点了。

    然后判断依据就是,下一个节点是否访问次数<=2

    int now=i+bit[k];//访问当前点1次
    f[now][k]=min(f[now][k],f[i][j]+dis[j][k]);
    

    如果没有看懂,可以在下面评论要求视频讲解

    代码解析

    /*
    f[i]表示当前访问的城市节点
    
    问题是当前城市访问次数需要统计
    
    于是放弃二进制,来存储这个城市是否访问过
    
    而是,采用三进制,表示这个城市的访问次数,0为未访问
    
    然后需要知道当前位于的城市
    
    所以f[i][j]表示状态为i,当前所在城市为j
    */
    #include <cstdio>
    #include <cstring>
    #include <algorithm>s
    using namespace std;
    const int N=211000;//3^10=59049
    //这里一定要开大N,因为第N位,我们可能要算2次,再加上其他位,所以开3倍最为保险
    //否则就会RE,我就是在这里挂掉的
    int f[N][13],bit[13],dis[21][21],n,m;
    #define state(a,b) ((a)/(bit[(b)])%3)//a状态b位置的访问次数 
    inline void init()
    {
    	bit[0]=1;
    	for(int i=1; i<=11; i++)//规定三进制的每一位
    		bit[i]=bit[i-1]*3;
    	while(scanf("%d%d",&n,&m)!=EOF)
    	{
    		memset(f,0x3f,sizeof(f));
    		memset(dis,0x3f,sizeof(dis));
    		for(int i=1; i<=m; i++)
    		{
    			int a,b,c;
    			scanf("%d%d%d",&a,&b,&c);
    			dis[a][b]=dis[b][a]=min(dis[a][b],c);
    		}
    		int ans=1e9;
    		for(int i=1; i<=n; i++)
    			f[bit[i]][i]=0;//把每个点作为出发点,费用均为0
    		for(int i=1; i<bit[n+1]; i++)//这里是访问所有状态
    		{
    			int ok=1;//假设所有的点都已经被访问过1次了
    			for(int j=1; j<=n; j++)
    			{
    				if (state(i,j)==0)//所有点并没有被访问过
    				{
    					ok=0;
    					continue;
    				}
    				//接下来开始转移节点
    				for(int k=1; k<=n; k++)
    				{
    					if (state(i,k)==2)//不可以再次访问
    						continue;
    					int now=i+bit[k];//访问当前点1次
    					f[now][k]=min(f[now][k],f[i][j]+dis[j][k]);
    					//从点j转移到点k,访问一次,计算费用
    				}
    			}
    			if (ok)//满足全部访问的基本条件了
    			{
    				for(int j=1; j<=n; j++)
    					ans=min(ans,f[i][j]);
    			}
    		}
    		if (ans==1e9)
    			ans=-1;
    		printf("%d
    ",ans);
    	}
    }
    signed main()
    {
    	init();
    	return 0;
    }
    
    /*Example
    2 1
    1 2 100
    3 2
    1 2 40
    2 3 50
    3 3
    1 2 3
    1 3 4
    2 3 10
    */
    
  • 相关阅读:
    python025 Python3 正则表达式
    python024 Python3 实例
    python023 Python3 标准库概览
    python022 Python3 面向对象
    python021 Python3 错误和异常
    列表和元组的元素不可被修改,但列表和元组的元素的元素可以被修改
    织梦标签
    自动添加QQ
    php把时间存入数据库为年月日时分秒类型
    PHP后台批量删除数据
  • 原文地址:https://www.cnblogs.com/gzh-red/p/14595016.html
Copyright © 2011-2022 走看看