hdu3001 Traveling (三进制状态压缩dp)

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 再从kj 看这样的路径会不会比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;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值