HDU 3001 Travelling 状态压缩dp+3进制

题意:一个人要旅行,他要去n个地方,且这n个地方每个地方最多可以走2次;

给m条路径,寻问最短花费

很明显的状态压缩,但是要求每个点最多只能走两次,就没办法标记当前点走过或是没走过,只能用三进制来表示

1代表地点1被走过一次、

2代表地点1被走过两次、

3(即10)代表地点2被走过一次、

4(即11)代表地点1被走过一次,地点2被走过一次、

5(即12)代表地点1被走过两次,地点2被走过一次、

附AC代码

#include<stdio.h>
#include<string.h>
int dis[15],dp[80000][15],dpp[80000][15];
int map[15][15];
int min1(int a,int b)
{
	if(a<b)
	return a;
	return b;
}
int main()
{
	int i,j,n,m,k;
	j=1;
	for(i=1;i<=11;i++)
	{
		dis[i]=j;
		j*=3;
	}
	for(i=0;i<dis[11];i++)
	{
		k=i;
		for(j=1;j<=11;j++)
		{
			dpp[i][j]=k%3;
			k/=3;
		}
	}

	while(scanf("%d%d",&n,&m)!=EOF)
	{
		int sum;
		memset(map,127,sizeof(map));
		sum=map[0][0];
		int cnt=map[0][0];
		while(m--)
		{
			scanf("%d%d%d",&i,&j,&k);
			if(k<map[i][j])//重边
			map[j][i]=map[i][j]=k;
		}
		memset(dp,127,sizeof(dp));
		for(i=1;i<=n;i++)
		{
			dp[dis[i]][i]=0;//
		}
		for(k=0;k<dis[n+1];k++)
		{
			int tot=1;
			for(i=1;i<=n;i++)
			{
				if(dpp[k][i]==0) tot=0;
				if(dp[k][i]==cnt)continue;
				for(j=1;j<=n;j++)
				{
					if(i==j)continue;//相同的地点不用更新
					if(dpp[k][j]>=2)continue;//两次不用更新,因为不能再走了
					if(map[i][j]==cnt)continue;//map[i][j]==cnt表示没有从i到j的路故不用更新
					int l=k+dis[j];
					dp[l][j]=min1(dp[l][j],dp[k][i]+map[i][j]);
				}
			}
			if(tot)
			{
				for(i=1;i<=n;i++)
				{
					sum=min1(sum,dp[k][i]);
				}
			}
		}
		if(sum==cnt)
		sum=-1;
		printf("%d\n",sum);
	}
	return 0;
} 
时间: 2024-10-14 06:49:57

HDU 3001 Travelling 状态压缩dp+3进制的相关文章

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(状态压缩 三进制)

Travelling Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 6600    Accepted Submission(s): 2144 Problem Description After coding so many days,Mr Acmer wants to have a good rest.So travelling is

HDU 3001(状态压缩DP)

题意:遍历所有的城市的最短路径,每个城市最多去两遍.将城市的状态用3进制表示. 状态转移方程为 dp[NewS][i]=min( dp[NewS][i],dp[S][j]+dis[i][j]) S表示遍历点的状态,i表示到达第i个城市. 在到第i个城市的时候看是否存在一个j城市的路径,然后再从j到i更短. #include <algorithm> #include <cstdio> #include <cstring> #define Max 1000001 #defi

hdu 4568(状态压缩dp)

题意:一张n*m的网格内每个点有话费,还有若干个宝藏,问一个人要走进去拿走所有宝藏在走出来的最小花费. 思路:看宝藏只有13个直接想到了状压dp[i][j]拿了哪几个前一个为j的最小花费,先bfs+优先队列预处理出最短路,然后记忆化搜索就可. 代码如下: 1 /************************************************** 2 * Author : xiaohao Z 3 * Blog : http://www.cnblogs.com/shu-xiaohao

hdu3001Travelling (状态压缩DP,三进制)

Travelling Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3611 Accepted Submission(s): 1132 Problem Description After coding so many days,Mr Acmer wants to have a good rest.So travelling is the b

hdu 3502 bfs+状态压缩dp

题意是给你n*m的矩阵     每个单位有一个数,-1表示不能走   >=0表示有有多少个能量能获得    问从左上角到右下角能获得的做大能量值(走一步消耗1单位能量) 思路:  先bfs求出所有线之间的最短距离(当然  有用的只有有能量值的点和起点,终点) 然后状态压缩dp  找到最大能量值    这里有几个注意的地方 状态尽量从1开始    减少数组的空间(爆了一次)   其次是bfs是只搜有能量的点     其它都差不多: #include<stdio.h> #include<

hdu 3681 二分+状态压缩dp+bfs

题意就不用多说了,开始想直接bfs+二分简化下做试试   果断超时,然后不得不用状态压缩dp(其实一开始就想这样做的,15个点   每个点都能走多次   绝逼状态压缩dp) 先bfs跑每个关键点之间的做短路径    再二分起点的能量值               状态压缩dp来判断     不说了    AC吧!!!!! #include<stdio.h> #include<string.h> #include<queue> #include<iostream&g

2010辽宁省赛E(Bellman_Ford最短路,状态压缩DP【三进制】)

#include<bits/stdc++.h>using namespace std;const int inf=0x3f3f3f3f;struct node{    int v,z,d,next;//存可以连接的点,用next存邻接表}a[10010];struct road{    int u,cnt,dis;//dis储存当前需要的钱数,即最短路算法里的权,u储存顶点,cnt储存组合数即状态压缩dp    road(int uu,int cntt,int diss)    {      

HDU 3001 Travelling 状压DP

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