首页 > 代码库 > HDU 3001 Travelling 状态压缩dp+3进制

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; 
} 



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