poj3001

D - Travelling
Time Limit:3000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

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

n(n<=10)个城市,m条道路,可以从任意一个城市出发,然后遍历所有城市,每个城市最多经过2次,问最短路程是多少

这个问题和旅行商问题类似,但是不同之处在于每个城市最多可以走2次,旅行商问题每个城市只走1次,然后回到出发点,一般都是从0点出发回到0点;在旅行商问题中用二进制表示该城市走过没走过得状态,在本题中需要用三进制表示走过的状态;

具体见代码

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <string>
#include <stdlib.h>

using namespace std;
const int inf = 0x3f3f3f3f;

int state[12]= {0,1,3,9,27,81,243,729,2187,6561,19683,59049}; ///几个直达状态
int mp[12][12];
int dp[12][60000];///3^10<60000
///3进制表示,dp[i][j]表示到i点的j状态 每个点状态有0(没走过)1(走了一次)2(走了两次)
int visit[12][60000];
int m,n;
int min(int a,int b)
{
    if(a<b)
        return a;
    return b;
}
void init()///visit[i][j]表示j状态到达i点几次
{
    memset(visit,0,sizeof(visit));
    for(int i=0; i<60000; i++
    {
        int t=i;
        for(int j=1; j<=10; j++)
        {
            visit[j][i]=t%3;
            t/=3;
            if (!t) break;
        }///类似与二进制状态的初始化,只不过这里不能用位运算
    }
}

void solve()
{
    int ans=inf;
    for(int i=0; i<=n; i++) dp[i][state[i]]=0;
    for(int i=0; i<state[n+1]; i++)///所有点仅经过这个点且只经过一次的
    {
        bool f=1;
        for(int j=1 ; j<=n; j++)
        {
            if (!visit[j][i]) f=0;
            if (dp[j][i]==inf) continue;
            for(int k=1; k<=n; k++)
            {
                if (k==j || mp[j][k]==inf || visit[k][i]>=2) continue;
                dp[k][i+state[k]]=min(dp[j][i]+mp[j][k],dp[k][i+state[k]]);
                ///k行(state[k]表示只经过k状态与i状态(原状态)之和)
                ///表示j点i状态通过的方法更新至k点[i+state[k]]状态的方法
            }
        }
        if (f)
        {
            for(int j=1; j<=n; j++)
            {
                ans=min(ans,dp[j][i]);///更新最小值
            }
        }
    }
    if (ans==inf) ans=-1;///无法完成
    printf("%d\n",ans);
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        memset(dp,inf ,sizeof(dp));
        memset(mp,inf ,sizeof(mp));
        for(int i=0; i<m; i++)
        {
            int u,v,num;
            scanf("%d%d%d",&u,&v,&num);
            mp[u][v]=mp[v][u]=min(mp[u][v],num);
        }
        solve();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值