Travelling
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5896 Accepted Submission(s): 1908
1 2 100
3 2
1 2 40
2 3 50
3 3
1 2 3
1 3 4
2 3 10
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;
}