Travelling

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5896    Accepted Submission(s): 1908

Problem Description
After coding so many days,Mr Acmer wants to have a good rest.So travelling is the best choice!He has decided to visit n cities(he insists on seeing all the cities!And he does not mind which city being his start station because superman can bring him to any city at first but only once.), and of course there are m roads here,following a fee as usual.But Mr Acmer gets bored so easily that he doesn't want to visit a city more than twice!And he is so mean that he wants to minimize the total fee!He is lazy you see.So he turns to you for help.
 
Input
There are several test cases,the first line is two intergers n(1<=n<=10) and m,which means he needs to visit n cities and there are m roads he can choose,then m lines follow,each line will include three intergers a,b and c(1<=a,b<=n),means there is a road between a and b and the cost is of course c.Input to the End Of File.
 
Output
Output the minimum fee that he should pay,or -1 if he can't find such a route.
 
Sample Input
2 1
1 2 100
3 2
1 2 40
2 3 50
3 3
1 2 3
1 3 4
2 3 10
 
Sample Output
100
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,三进制)的更多相关文章

  1. Travelling(HDU3001+状压dp+三进制+最短路)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题目: 题意:n个城市,m条边,每条边都有一个权值,问你经过所有的城市且每条边通过次数不超过两次 ...

  2. HDU3001 Traveling (状压dp+三进制+Tsp问题总结)

    (1)这道题最多可以走两次,所以有0, 1, 2三种状态,所以我们要用三进制 如果要用三进制,就要自己初始化两个数组, 一个是3的n次方,一个是三进制数的第几位的数字是什么 void init() { ...

  3. HDU - 3001 Travelling 状压dp + 三进制 [kuangbin带你飞]专题二

    终于刷完搜索专题了. 题意:给定n个城市,每个城市参观不能超过两次,两个城市之间有道路通过需要花费X,求通过能所有城市的最小花费. 思路:每个城市有三个状态0,1,2,可用三进制存储所有城市的访问状态 ...

  4. POJ1185 状压dp(二进制//三进制)解法

    很显然这是一道状压dp的题目 由于每个最优子结构和前两行有关,一个显而易见的想法是用三维dp[i][j][k]用来记录在第i行下为j状态,i - 1行为k状态时的最大值,然而dp[100][1 < ...

  5. hdu 3001 Travelling 经过所有点(最多两次)的最短路径 三进制状压dp

    题目链接 题意 给定一个\(N\)个点的无向图,求从任意一个点出发,经过所有点的最短路径长度(每个点至多可以经过两次). 思路 状态表示.转移及大体思路 与 poj 3311 Hie with the ...

  6. HDU 3001 Travelling (状压DP,3进制)

    题意: 给出n<=10个点,有m条边的无向图.问:可以从任意点出发,至多经过同一个点2次,遍历所有点的最小费用? 思路: 本题就是要卡你的内存,由于至多可经过同一个点2次,所以只能用3进制来表示 ...

  7. 『数 变进制状压dp』

    数 Description 给定正整数n,m,问有多少个正整数满足: (1) 不含前导0: (2) 是m的倍数: (3) 可以通过重排列各个数位得到n. \(n\leq10^{20},m\leq100 ...

  8. 状压dp-----三进制

    三进制的状压dp要先预处理3^n以及每一个数的每一位 例题 hdu3001 题意: 给定n 个城市已经 m 条路 以及对应路费 c,要求遍历所有城市最少的路费,每个城市不能超过2次. 题解: 看代码吧 ...

  9. poj1038 Bugs Integrated,Inc. (状压dp)

    题意:N*M的矩阵,矩阵中有一些坏格子,要在好格子里铺2*3或3*2的地砖,问最多能铺多少个. 我的方法好像和网上流传的方法不太一样...不管了.... 由数据范围很容易想到状压dp 我们设某个状态的 ...

  10. 2018.10.05 NOIP模拟 上升序列(状压dp)

    传送门 状压dp好题. 首先需要回忆O(nlogn)O(nlog n)O(nlogn)求lislislis的方法,我们会维护一个单调递增的ddd数组. 可以设计状态f(s1,s2)f(s1,s2)f( ...

随机推荐

  1. com.netflix.zuul.exception.ZuulException: Forwarding error

    一.问题描述 在使用Spring Cloud的zuul组件,做路由转发时,每次重新启动后端服务,头几次调用都会出现com.netflix.zuul.exception.ZuulException: F ...

  2. hihocoder-1415 后缀数组三·重复旋律3 两个字符串的最长公共子串

    把s1,s2拼接,求Height.相邻的Height判断左右串起点是否在两个串中,另外对Height和s1.length()-SA[i-1]取min. #include <iostream> ...

  3. J - Jesus Is Here HDU - 5459 (递推)

    大意: 定义$f_1="c",f_2="ff",f_n=f_{n-2}+f_{n-1}$, 求所有"cff"的间距和. 记录c的个数, 总长 ...

  4. 区间逼近 牛客寒假1 小a的排列

    做法:模拟 萌区间也就是这个区间里的数是一段连续的数 做法的话是先找出题目x,y的位置,记为l,r,然后找出l,r内的最大最小值,又因为萌区间要求数是连续的,就从这段连续数最小的开始到最大的,确定缩放 ...

  5. h5手机端禁止缩放问题

    最近测试html5页面,发现默认都允许用户缩放页面,或者在屏幕双击放大或缩小.即相当于这样设置 <meta name="viewport" content="wid ...

  6. CF-877E-线段树+哈希

    http://codeforces.com/problemset/problem/877/E 给出一颗有根树,没个节点上有一个值0/1,有两种操作,一个是选中一个节点,对他所对应的那个子树上所有节点的 ...

  7. 灵活运用 SQL SERVER FOR XML PATH 转

    灵活运用 SQL SERVER FOR XML PATH   FOR XML PATH 有的人可能知道有的人可能不知道,其实它就是将查询结果集以XML形式展现,有了它我们可以简化我们的查询语句实现一些 ...

  8. JdbcTemplate查询返回JavaBean的几种方法

    关于JdbcTemplate的官方描述如下: org.springframework.jdbc.core.JdbcTemplate 大约的讲,将JdbcTemplate返回的list结果集生成Java ...

  9. 【Linux】bash shell学习

    Bash Shell Linux系统的合法shell都写入/etc/shells这个文件,默认使用的shell版本称为“Bourne Again Shell(简称bash)” 用户登录时系统会分配一个 ...

  10. C++ leetcode::Reverse Integer

    第一天上课,数据库老师说对于计算机系的学生,凡是在课本上学到的专业知识都是过时的.深以为然,感觉大学两年半真的不知道学了什么,为未来感到担忧,C++也不敢说是精通,入门还差不多.最近丧的不行,不管怎么 ...