您的位置:首页 > 其它

poj3001

2016-03-27 16:25 281 查看
D - Travelling
Time Limit:3000MS     Memory Limit:32768KB     64bit IO Format:%I64d
& %I64u
Submit Status Practice HDU
3001

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: