hdu3001(状压dp,三进制)
Travelling
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5896 Accepted Submission(s): 1908
1 2 100
3 2
1 2 40
2 3 50
3 3
1 2 3
1 3 4
2 3 10
90
7
以下文字转载于https://www.cnblogs.com/martinue/p/5490432.html
这题的状态压缩不是二进制了,换到了三进制!!
这是为何??
题目中明确的说了每个点最多走2次,也就是说压缩为二进制并不能直接求出结果了,因为二进制只能代表一个点是否被走过的状态,而具体走过了几次却并不能记录!!然而我们题目要求可以走两次呀!怎么办?!大牛们想到了办法,压缩为三进制!
将状态压缩为三进制之后,那么显然,我们的状态数增多了,那么这些增加的状态数代表着什么呢?
举个栗子:将46化为3进制之后是1201,那么我们就可以暴力的来表示第1个点去过1次,第2个点没去过,第3个点去过2次,第4个点也去过1次!
用上面这个例子来说明一个问题,就是我们用三进制来压缩了题目要求的所有的状态,因为每个数位可以是2了,这个2是有意义的!就是表示某个点是否去过2次!
然后dp部分是状态压缩的常规解法,主要在于理解为何要化为3进制的状态压缩。
#include<stdio.h>
#include<string.h>
#define Max 0x3fffffff
int dp[60000][12];//记录dp[i][j]当第i种情况时以j地点为结束地点的总路程,例:46=(1201)3;则dp[46][0](i=46,j=0)代表当1走1次,2走0次,3走2次,4走1次时最后以1为终点所走路程。
int num[12];//记录3的几次方{1,3,9。。。。59049(3的10次方)}
int mp[12][12];//记录a到b的路程
int dight[60000][12];//记录第i中种情况j号位走了多少次j=(0---->n-1)
int min(int a,int b)
{
return (a>b)?b:a;
}
int init()//初始化所需条件
{
int i,j;
int a;
num[0]=1;
for(i=1;i<=10;i++)
num[i]=num[i-1]*3;
for(i=0;i<num[10];i++)
{
a=i;
for(j=0;a!=0;j++)
{
dight[i][j]=a%3;
a=a/3;
//printf("%d",dight[i][j]);
}
//printf("\n");
}
return 0;
}
int main()
{
int n,m;
int i,j,k;
int a,b,c;
int flag;
int mx;
init();
while(scanf("%d%d",&n,&m)!=EOF)
{
` mx=Max;
for(i=0;i<num[n];i++)//初始化第i种情况以j为终点的路程
{
for(j=0;j<n;j++)
dp[i][j]=Max;
}
for(i=0;i<n;i++)
{
dp[num[i]][i]=0;//初始化起点,因为num[i][i]转换为3进制时就等于只有i号为走了一次的情况 ,而它又以i为终点,所以这就是以i号为起点的情况
mp[i][i]=0;
for(j=0;j<i;j++)
mp[i][j]=mp[j][i]=Max;
}
for(i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
mp[a-1][b-1]=mp[b-1][a-1]=min(mp[a-1][b-1],c);//我们是从0-->n-1的,记得减一
}
for(i=0;i<num[n];i++)
{
flag=1;
for(j=0;j<n;j++)
{
if(dight[i][j]==0)//记录是否每个位置都到过
flag=0;
if(dp[i][j]!=Max)//当第i种情况时以j为终点有一段路程可以满足的这个条件时
{
for(k=0;k<n;k++)//因为dp[i][j]这种情况存在,所以可以更新dp[i+num[k]][k]的这种情况,i+num[k]相当于在i这种情况下在k号位置加一,然后就以k为终点。
{
if(dight[i][k]<=1&&j!=k&&mp[j][k]!=Max)//判断满足条件,由题意可知,k号位置经历的次数不能超过两次,所以dight[i][k]<=1,并且要有路从j到k。
{
int nt=i+num[k];//当第i种情况时k号位加一的情况
dp[nt][k]=min(dp[nt][k],dp[i][j]+mp[j][k]);//更新
}
}
}
}
if(flag==1)
{
for(j=0;j<n;j++)
mx=min(mx,dp[i][j]);//更新最短路程
}
}
if(mx==Max)
printf("-1\n");
else
printf("%d\n",mx);
}
return 0;
}
hdu3001(状压dp,三进制)的更多相关文章
- Travelling(HDU3001+状压dp+三进制+最短路)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题目: 题意:n个城市,m条边,每条边都有一个权值,问你经过所有的城市且每条边通过次数不超过两次 ...
- HDU3001 Traveling (状压dp+三进制+Tsp问题总结)
(1)这道题最多可以走两次,所以有0, 1, 2三种状态,所以我们要用三进制 如果要用三进制,就要自己初始化两个数组, 一个是3的n次方,一个是三进制数的第几位的数字是什么 void init() { ...
- HDU - 3001 Travelling 状压dp + 三进制 [kuangbin带你飞]专题二
终于刷完搜索专题了. 题意:给定n个城市,每个城市参观不能超过两次,两个城市之间有道路通过需要花费X,求通过能所有城市的最小花费. 思路:每个城市有三个状态0,1,2,可用三进制存储所有城市的访问状态 ...
- POJ1185 状压dp(二进制//三进制)解法
很显然这是一道状压dp的题目 由于每个最优子结构和前两行有关,一个显而易见的想法是用三维dp[i][j][k]用来记录在第i行下为j状态,i - 1行为k状态时的最大值,然而dp[100][1 < ...
- hdu 3001 Travelling 经过所有点(最多两次)的最短路径 三进制状压dp
题目链接 题意 给定一个\(N\)个点的无向图,求从任意一个点出发,经过所有点的最短路径长度(每个点至多可以经过两次). 思路 状态表示.转移及大体思路 与 poj 3311 Hie with the ...
- HDU 3001 Travelling (状压DP,3进制)
题意: 给出n<=10个点,有m条边的无向图.问:可以从任意点出发,至多经过同一个点2次,遍历所有点的最小费用? 思路: 本题就是要卡你的内存,由于至多可经过同一个点2次,所以只能用3进制来表示 ...
- 『数 变进制状压dp』
数 Description 给定正整数n,m,问有多少个正整数满足: (1) 不含前导0: (2) 是m的倍数: (3) 可以通过重排列各个数位得到n. \(n\leq10^{20},m\leq100 ...
- 状压dp-----三进制
三进制的状压dp要先预处理3^n以及每一个数的每一位 例题 hdu3001 题意: 给定n 个城市已经 m 条路 以及对应路费 c,要求遍历所有城市最少的路费,每个城市不能超过2次. 题解: 看代码吧 ...
- poj1038 Bugs Integrated,Inc. (状压dp)
题意:N*M的矩阵,矩阵中有一些坏格子,要在好格子里铺2*3或3*2的地砖,问最多能铺多少个. 我的方法好像和网上流传的方法不太一样...不管了.... 由数据范围很容易想到状压dp 我们设某个状态的 ...
- 2018.10.05 NOIP模拟 上升序列(状压dp)
传送门 状压dp好题. 首先需要回忆O(nlogn)O(nlog n)O(nlogn)求lislislis的方法,我们会维护一个单调递增的ddd数组. 可以设计状态f(s1,s2)f(s1,s2)f( ...
随机推荐
- com.netflix.zuul.exception.ZuulException: Forwarding error
一.问题描述 在使用Spring Cloud的zuul组件,做路由转发时,每次重新启动后端服务,头几次调用都会出现com.netflix.zuul.exception.ZuulException: F ...
- hihocoder-1415 后缀数组三·重复旋律3 两个字符串的最长公共子串
把s1,s2拼接,求Height.相邻的Height判断左右串起点是否在两个串中,另外对Height和s1.length()-SA[i-1]取min. #include <iostream> ...
- J - Jesus Is Here HDU - 5459 (递推)
大意: 定义$f_1="c",f_2="ff",f_n=f_{n-2}+f_{n-1}$, 求所有"cff"的间距和. 记录c的个数, 总长 ...
- 区间逼近 牛客寒假1 小a的排列
做法:模拟 萌区间也就是这个区间里的数是一段连续的数 做法的话是先找出题目x,y的位置,记为l,r,然后找出l,r内的最大最小值,又因为萌区间要求数是连续的,就从这段连续数最小的开始到最大的,确定缩放 ...
- h5手机端禁止缩放问题
最近测试html5页面,发现默认都允许用户缩放页面,或者在屏幕双击放大或缩小.即相当于这样设置 <meta name="viewport" content="wid ...
- CF-877E-线段树+哈希
http://codeforces.com/problemset/problem/877/E 给出一颗有根树,没个节点上有一个值0/1,有两种操作,一个是选中一个节点,对他所对应的那个子树上所有节点的 ...
- 灵活运用 SQL SERVER FOR XML PATH 转
灵活运用 SQL SERVER FOR XML PATH FOR XML PATH 有的人可能知道有的人可能不知道,其实它就是将查询结果集以XML形式展现,有了它我们可以简化我们的查询语句实现一些 ...
- JdbcTemplate查询返回JavaBean的几种方法
关于JdbcTemplate的官方描述如下: org.springframework.jdbc.core.JdbcTemplate 大约的讲,将JdbcTemplate返回的list结果集生成Java ...
- 【Linux】bash shell学习
Bash Shell Linux系统的合法shell都写入/etc/shells这个文件,默认使用的shell版本称为“Bourne Again Shell(简称bash)” 用户登录时系统会分配一个 ...
- C++ leetcode::Reverse Integer
第一天上课,数据库老师说对于计算机系的学生,凡是在课本上学到的专业知识都是过时的.深以为然,感觉大学两年半真的不知道学了什么,为未来感到担忧,C++也不敢说是精通,入门还差不多.最近丧的不行,不管怎么 ...