HDU3001(状压DP,三进制)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001

Travelling

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

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

题意:给出一个图,问经过所有点的最小边权和,每个点最多经过两次。如果无法找到一条路径,则输出-1.

解题思路,设dp【i】【j】为经过j状态时,且最后到达i点的最小权值和。状态j为三进制下,每个数位代表经过每个点的次数。

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
int dp[15][200000];
int mp[15][15];
int bit[15];
int pos[15];
int main(){
    int n,m;
    bit[0]=1;
    for(int i=1;i<15;i++){
        bit[i]=bit[i-1]*3;
    }
    while(scanf("%d%d",&n,&m)!=EOF){
        memset(mp,0x3f,sizeof(mp));
        memset(dp,0x3f,sizeof(dp));
        int a,b,c;
        for(int 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);
        }
        for(int i=0;i<n;i++){
            dp[i][bit[i]]=0;
        }
        for(int i=1;i<bit[n];i++){
            int tem=i;
            for(int j=0;j<n;j++){
                pos[j]=tem%3;
                tem/=3;
            }
            for(int j=0;j<n;j++){
                if(pos[j]!=0){
                    for(int k=0;k<n;k++){
                        if(k!=j&&pos[k]<2){
                            dp[k][i+bit[k]]=min(dp[k][i+bit[k]],dp[j][i]+mp[j][k]);
                        }
                    }
                }
            }
        }
        int ans=inf;
        for(int i=0;i<n;i++){
            for(int j=1;j<bit[n];j++){
                int flag=1;
                int tem=j;
                for(int k=0;k<n;k++){
                    if(tem%3==0){
                        flag=0;
                        break;
                    }
                    tem/=3;
                }
                if(flag)ans=min(dp[i][j],ans);
            }
        }
        if(ans==inf)puts("-1");
        else
        printf("%d\n",ans);
    }
//    printf("%d\n",bit[11]-1);
    return 0;
} 

原文地址:https://www.cnblogs.com/Zhi-71/p/11440659.html

时间: 2024-10-28 01:17:29

HDU3001(状压DP,三进制)的相关文章

hdu 3001(状压dp+三进制)

不管是几进制,都用的是逻辑上概念,(上次六进制是用来转化多维数据)核心思路是TSP.这里的预处理比较巧妙,计算出了每种状态下各个位上的模vis[][]. TSP:dp[i][j] 在i状态下,以j结尾的最优解.两种转移都行:我为人人,人人为我. #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define maxn 60000 #define inf 0x3

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

题目链接 题意 给定一个\(N\)个点的无向图,求从任意一个点出发,经过所有点的最短路径长度(每个点至多可以经过两次). 思路 状态表示.转移及大体思路 与 poj 3311 Hie with the Pie 经过所有点(可重)的最短路径 floyd + 状压dp 相同. 但,因为是每个点 至多可以经过两次,所以应该用 三进制 来表示状态. 因为三进制不能直接通过移位来表示,所以要 预处理 出每个数字\(state\)的三进制表示中每一位\(i\)上的值\(dig[state][i]\). 注意

UVA - 10817 Headmaster&#39;s Headache (状压类背包dp+三进制编码)

题目链接 题目大意:有S门课程,N名在职教师和M名求职者,每名在职教师或求职者都有自己能教的课程集合以及工资,要求花费尽量少的钱选择一些人,使得每门课程都有至少两人教.在职教师必须选. 可以把“每个课程已经分别有几个人教”作为状态来进行转移,每个人能教的课程集合作为“物品重量”,工资作为“价值”来更新dp值,类似01背包,每放进一个人,从后往前更新即可. 状态的表示可以用三进制编码,为了写起来舒服,我写了个结构体作为状态和编码转换的桥梁,也可以进行状态的“加法运算”,虽然速度比较慢就是了~~ 有

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

题意: 给出n<=10个点,有m条边的无向图.问:可以从任意点出发,至多经过同一个点2次,遍历所有点的最小费用? 思路: 本题就是要卡你的内存,由于至多可经过同一个点2次,所以只能用3进制来表示,3进制可以先将表打出来.在走的时候注意只能走2次,其他的和普通的TSP状压DP是一样的.注意点:重边,自环等等,老梗了. 1 //#include <bits/stdc++.h> 2 #include <iostream> 3 #include <cstdio> 4 #i

hdu 3341 Lost&#39;s revenge(AC自动机+变进制状压DP)

题目链接:hdu 3341 Lost's revenge 题目大意:给定一些需要匹配的串,然后在给定一个目标串,现在可以通过交换目标串中任意两个位置的字符,要求最 后生成的串匹配尽量多的匹配串,可以重复匹配. 解题思路:这题很明显是AC自动机+DP,但是dp的状态需要开40?40?40?40(记录每种字符的个数),空间承受 不了,但是其实因为目标串的长度有限,为40:所以状态更本不需要那么多,最多只有10?10?10?10,但是通过 40进制的hash转换肯定是不行,可以根据目标串中4种字符的个

HDU 3001 Travelling 状压DP

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题意:还是环游地图的问题,只不过这回旅行者对自己有着严格的要求,地图上每个点的经过次数不能超过两次. 思路:依然是状压DP问题,根上一道很像,只不过这次对于每个点来说有三种状态,分别是未经过,经过一次,经过两次.所以要用三进制的数来进行状态压缩,这个关键点想明白了其他的和上一道基本一样了.对于我来说需要注意的是:能够到达某一个点经过了两次的状态的前一个状态是这个点已经经过了一次的状态,而不是从来未

POJ 1038 状压DP

一个公司生产一种2*3规模的芯片,但是原材料上面有一些地方是不能用来当作芯片材料的,给出原料大小,及上面不能做原料的点,问你怎么分解,可以使生成芯片最大化. 对M进行三进制状压 last数组存储第i-1行和i-2行状态,cur数组存储i行和i-1行状态 cur[k]=2; // 本行k位置和上行k位置都不可用 cur[k]=1; // 本行k位置可用,上行k位置不可用 cur[k]=0; // 本行和上行位置k均可用 必须用滚动数组,否则爆内存 #include "stdio.h" #

[DP总结]状压DP

顾名思义,是用将状态进行二进制压缩成集合的形式来方便DP转移的方法. 一些常用的代码表示如下 i & j //取状态i,j重合部分 i ^ j //取状态i,j不同部分 i | j //合并状态i,j (1 << N) - 1 //表示111-1(N个1) 1 << i - 1 //表示00100-0(1后面有i-1个0,也就是有且仅有二进制下第i位为1) for (int i = 0; i < n; ++ i) if (x & (1 << i))

POJ 1038 Bugs Integrated Inc (复杂的状压DP)

\(POJ~1038~~*Bugs~Integrated~Inc:\) (复杂的状压DP) \(solution:\) 很纠结的一道题目,写了大半天,就想练练手,结果这手生的.其实根据之前那道炮兵阵地就不应该写的,但是总觉得自己的思路会好一些,码量又小. 博主的核心思路其实就是用一个二进制数来压缩三行的状态,因为二进制的左移右移很方便.然后就是如果三进制会很不好转移. 我们可以用一个二进制数来预处理压缩出第 \(i\) 往下三行的障碍状态,前 \(m\) 个二进制位表第 \(i\) 行,中间 \

涂抹果酱(状压dp)

涂抹果酱 题目描述 Tyvj两周年庆典要到了,Sam想为Tyvj做一个大蛋糕.蛋糕俯视图是一个N×M的矩形,它被划分成N×M个边长为1×1的小正方形区域(可以把蛋糕当成N行M列的矩阵).蛋糕很快做好了,但光秃秃的蛋糕肯定不好看!所以,Sam要在蛋糕的上表面涂抹果酱.果酱有三种,分别是红果酱.绿果酱.蓝果酱,三种果酱的编号分别为1,2,3.为了保证蛋糕的视觉效果,Admin下达了死命令:相邻的区域严禁使用同种果酱.但Sam在接到这条命令之前,已经涂好了蛋糕第K行的果酱,且无法修改. 现在Sam想知