Travelling
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 9936 Accepted Submission(s): 3198
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
Source
2009 Multi-University Training Contest 11 - Host by HRBEU
Recommend
gaojie
算法分析:
题意:
10个点的TSP问题,但是要求每个点最多走两边,不是只可以走一次。
分析:
我们设dp[j][i]存终点为j的通过状态为i的最短距离
状态转移方程:dp[j][i]=min(dp[j][i],dp[k][l]+mp[k][j]);
j表示终点, i为二进制表示状态 ,1表示经过, 0表示不经过 把所有可能的路径排列出来 找最小值
l表示i的第j位从1变成0之后的三进制数
k表示中转点 先从去掉一个经过点的位置到k 再从k到j 看这样的路径会不会比i的情况短
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
int bit[12]={0,1,3,9,27,81,243,729,2187,6561,19683,59049};
int tri[60000][11];//用tri[i][j]存i状态的第j位
int dp[11][60000];//dp[i][j]存终点为i的通过状态为j的最短距离
int mp[11][11];//mp[i][j]存i到j的最短距离
int main()
{
int n,a,b,m,c,ans,flag;
for(int i=0;i<59050;++i)//预处理节约时间,预处理每个状态的第k位是什么
{
int t=i;
for(int j=1;j<=10;++j)
{
tri[i][j]=t%3;
t/=3;
if(t==0)break;
}
}
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(dp,0x3f,sizeof(dp));
memset(mp,0x3f,sizeof(mp));
for(int i=0;i<=n;i++)//初始状态
dp[i][bit[i]]=0;
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
if(c<mp[a][b]) mp[a][b]=mp[b][a]=c;
}
ans=inf;
for(int i=0;i<bit[n+1];i++)//排列所有状态
{
flag=1;//标记i状态是否已经经过所有点
for(int j=1;j<=n;j++)//选一个终点
{
if(!tri[i][j])//判断终点位是否为0
{
flag=0;//有一个为零则还没有经过所有点
continue;
}
if(i==j) continue;
for(int k=1;k<=n;k++)
{
int l=i-bit[j];// l表示i的第j位从1变成0之后的三进制数
if(tri[i][k]==0) continue;//别掉了。。
dp[j][i]=min(dp[j][i],dp[k][l]+mp[k][j]);
}
}
if(flag)//从所有经过所有点的情况中 找距离最小的点
for(int j=1;j<=n;j++)
ans=min(ans,dp[j][i]);
}
if(ans==inf) printf("-1\n");
else printf("%d\n",ans);
}
return 0;
}