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( ...
随机推荐
- Fiddler抓包—搞定接口测试
·包的定义 在包交换网络里,单个消息被划分为多个数据块,这些数据块称为包,它包含发送者和接受者的地址信息.这些包然后沿着不同的路径在一个或多个网络中传输,并且在目的地重新组合. ·应用 简 ...
- gitlab 集成Jenkins
项目:使用git+jenkins实现持续集成 开始构建 General 源码管理 我们安装的是Git插件,还可以安装svn插件 我们将git路径存在这里还需要权限认证,否则会出现error 我 ...
- CF数据结构练习
1. CF 438D The Child and Sequence 大意: n元素序列, m个操作: 1,询问区间和. 2,区间对m取模. 3,单点修改 维护最大值, 取模时暴力对所有>m的数取 ...
- Financiers Game CodeForces - 737D (博弈论)
直接暴力区间DP的话是$O(n^3)$, 关键注意到每步走的距离差不超过1, 所以差最大是$O(\sqrt{n})$的, 所以实际上有用的状态是$O(n^2)$的, 可以通过.
- CoordinatorLayout、AppBarLayout、CollapsingToolbarLayout的用法,让Toolbar与系统栏融为一体
CoordinatorLayout其实是加强版的FrameLayout布局,可以监听期所有子控件的各种事件,由Design Support库提供的,能体现Material Design 的魔力.能解决 ...
- uva-11324-SCC+dp
https://vjudge.net/problem/UVA-11324 给出一幅有向图,问最大能找到多少个节点,使得这些节点中任意两个节点之间都至少有一条可达路径. 找出SCC后缩点求权重最大路即可 ...
- 查看某一职责下对应的菜单&功能&请求(转)
原文地址:查看某一职责下对应的菜单&功能&请求 查看菜单&功能 SELECT res.RESPONSIBILITY_NAME 职责名称, menu.MENU_NAME 菜单编码 ...
- Git:创建与合并分支
1.1创建dev分支,使用命令符 git branch 分支名称. 1.2将HEAD指针切换到dev分支,使用命名符git checkout 分支名称. 注:创建并且转移可以合并为一个步骤,使用命令符 ...
- MapReduce- 数据的排序处理
MapReduce- 数据的排序处理 package com.huhu.day02; import java.io.DataInput; import java.io.DataOutput; impo ...
- js 手机号码和电话号码正则校验
checkPhone() { var mobile = ''; var tel = /^0\d{2,3}-?\d{7,8}$/; var phone = /^(((13[0-9]{1})|(15[0- ...