HDU 3001

题目中说明每个城市至少要走一次,至多走2次,因此要用到三进制压缩,然后就是状态转移方程了。

这道题就处理三进制的地方麻烦一点。同时注意,在选择最小长度时,一定是要每一个点都经过至少一次的,即是状态的每一个三进制位均 >=1.

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int inf=1<<30;
struct Edge{
	int u,v,c;
	int next;
}edge[2000];
int tot,n,m;
int head[15];
int dp[60000][11],tir[60000][12],s[12];

struct Status{
	int i,j,c;
	Status(){}
	Status(int ii,int jj,int cc){i=ii,j=jj,c=cc;}
}que[1800000];
int hed,tail;

void addedge(int u,int v,int c){
	edge[tot].u=u;
	edge[tot].v=v;
	edge[tot].c=c;
	edge[tot].next=head[u];
	head[u]=tot++;
}

void init() {
    s[0]=1;
    for(int i=1; i<=10; i++)
        s[i]=s[i-1]*3;
    for(int i=0; i<=s[10]; i++){
        int t=i;
        for(int j=0; j<10; j++){
            tir[i][j]=t%3;
            t/=3;
        }
    }
}

void slove(){
	int u,v;
	int ans=inf;
	while(hed<tail){
		Status tmp=que[hed++];
		if(dp[tmp.i][tmp.j]<tmp.c) continue;
		bool flag=true;
		for(int i=0;i<n;i++){
			if(tir[tmp.i][i]==0) {flag=false; break ;}
		}
		if(flag) ans=min(ans,dp[tmp.i][tmp.j]);
		u=tmp.j;
		for(int e=head[tmp.j];e!=-1;e=edge[e].next){
			v=edge[e].v;
			if(v==u||tir[tmp.i][v]==2) continue;
			int states=tmp.i+s[v];
			if(dp[states][v]>tmp.c+edge[e].c){
				dp[states][v]=tmp.c+edge[e].c;
				que[tail++]=Status(states,v,dp[states][v]);
			}
		}
	}
	printf("%d\n",ans==inf?-1:ans);
}

int main(){
	int u,v,c;
	init();
	while(scanf("%d%d",&n,&m)!=EOF){
		memset(head,-1,sizeof(head));
		tot=0;
		for(int i=0;i<m;i++){
			scanf("%d%d%d",&u,&v,&c);
			u--; v--;
			addedge(u,v,c);
			addedge(v,u,c);
		}
		for(int i=0;i<s[n];i++){
			for(int j=0;j<n;j++)
			dp[i][j]=inf;
		}
		hed=tail=0;
		for(int i=0;i<n;i++){
			int st=s[i];
			dp[st][i]=0;
			que[tail++]=Status(st,i,0);
		}
		slove();
	}
	return 0;
}

  

时间: 2024-08-22 16:59:51

HDU 3001的相关文章

HDU 3001 状压DP

有道状压题用了搜索被队友骂还能不能好好训练了,, hdu 3001 经典的状压dp 大概题意..有n个城市 m个道路  成了一个有向图.n<=10: 然后这个人想去旅行.有个超人开始可以把他扔到任意的一个城市..然后他就在城市之间游荡.要满足他要游玩所有的城市..并且.每个城市最多去两次.要求路程最短..如果他不能游完所有的城市,,那么..就输出-1  否则 输出最短距离 如果用搜索...不靠谱  然后用搜索,, 怎么压缩?? 用一个整型数 i 表示他现在的状态..显然一个城市是要用两位..00

hdu 3001 Travelling TSP变形 三进制状压dp

// hdu 3001 TSP问题的变形 // 这次到每个点最多两次,所以可以用三进制的类推 // dp[S][u]表示当前在u点访问状态为S时所得到的最小的开销 // 采用刷表法,即用当前的状态推出它所能转移的状态 // dp[S][u] 可以到达的状态为dp[S+state[v]][v](dist[u][v]!=inf) // dp[S+state[v]][v] = max(dp[S+state[v]][v],dp[S][u]+dist[u][v]); // 其中每个点最多访问2次 // 技

HDU 3001 Travelling (三进制状态压缩 DP)

题意:有 n 个city,可以选择任一城市作为起点,每个城市不能访问超过2次, 城市之间有权值,问访问全部n个城市需要的最小权值. 思路:因为每个城市可以访问最多两次,所以用三进制表示访问的状态. 详细见代码注释!!!! #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #include<cmath> #inclu

HDU 3001 Travelling 状压DP

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

HDU 3001 Travelling:TSP(旅行商)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题意: 有n个城市,m条双向道路,每条道路走一次需要花费路费v.你可以将任意一个城市作为起点出发,然后遍历每一个城市,并保证同一个城市最多经过2次.问你遍历这些城市的最小费用是多少. 题解: 传统的TSP问题中,每个城市只能经过一次,做法为三重for循环,分别枚举城市的state.现在所处位置i.下一步要到达的城市j. 核心Code: 1 memset(dp,-1,sizeof(dp)); 2

HDU 3001 Travelling

Travelling Time Limit: 3000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 300164-bit integer IO format: %I64d      Java class name: Main After coding so many days,Mr Acmer wants to have a good rest.So travelling is the best

HDU 3001 Travelling(状态压缩DP+三进制)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题目大意:有n个城市,m条路,每条路都有一定的花费,可以从任意城市出发,每个城市不能经过两次以上,要求经过所有城市并且花费最少,求出最小花费. 解题思路:三进制的状态压缩DP,跟二进制还是有一点不一样的,因为三进制没有直接的位运算,还要自己先做处理利用num[i][j]记录数字i各位的三进制表示方便计算,其他的就跟二进制状态压缩没有太大区别了.还有注意: ①开始要将n个起点初始化,dp[bit

HDU 3001 Travelling 3进制状压dp

题意:10个点,若干条边,边有花费,每个点最多走两次,求走过所有点,花费最少 分析:因为每个点最多走两次,所以联想到3进制,然后枚举状态,就行了(我也是照着网上大神的代码写的) #include <cstdio> #include <iostream> #include <cstring> #include <cstdlib> #include <vector> #include <string> #include <cmath

HDU 3001【状态压缩DP】

题意: 给n个点m条无向边. 要求每个点最多走两次,要访问所有的点给出要求路线中边的权值总和最小. 思路: 三进制状态压缩DP,0代表走了0次,1,2类推. 第一次弄三进制状态压缩DP,感觉重点是对数据的预处理,利用数组分解各个位数,从而达到类似二进制的目的. 然后就是状态的表示,dp[s][i]表示状态s时到达i的最优值. 状态转移也一目了然,不废话. #include<stdio.h> #include<string.h> #include<algorithm> u

HDU - 3001 Travelling (状态压缩)

题目大意:有一个人要去旅游,他想要逛遍所有的城市,但是同一个城市又不想逛超过2次.现在给出城市之间的来往路费,他可以选择任意一个点为起点.问逛遍所有城市的最低路费是多少 解题思路:这题和POJ - 3311 Hie with the Pie相似 这里的状态标记要用三进制数来表示,就可以表示每个城市去过的次数了 设dp[i][state]为现在在i城市,逛过的城市状态为state的最低路费 状态转移方程: dp[i][S + i城市标记] = min(dp[i][S + i城市标记], dp[j]