旅游
时间限制:
1000 ms | 内存限制:
65535 KB
难度:
4
-
描述
-
飘谊到了S国旅游,S国有n个城市,城市之间有许多观光道路,为了看到最多的风景,飘谊希望从某个城市出发,走完所有的观光道路,并且回到出发点。飘谊想知道他走完观光道路并回到源点的最短路径
-
输入
-
输入包含多组测试数据。
每组输入的第一行为2个正整数n和m(n<=15,m<1000),n表示城市的个数,m表示观光道路的个数。接下来m行,每行输入3个正整数u,e,l(1<=u,e<=n,1<=l<=5000),表示标号为u和e的城市由一条路相连,长度为l。任意两个城市之间可能会由多条路相连而且路的长度也可能会相等。每条路都是双向可通行的。任意两个城市是可以相互到达的。
输出
- 对于每组输入,输出最短路。 样例输入
-
4 5 1 2 3 2 3 4 3 4 5 1 4 10 1 3 12
样例输出
-
41
-
输入包含多组测试数据。
G图是欧拉图,所以G图的路径就是只走一次的路径。不在G图的边可以想象是“挂”在G图上的,要保证G图的一笔画性,就需要走两次(一出一回)来处理不在G图的边。
因为G图是原图的子图。要寻找它需要删边,这点很不好处理。
可以分析知题目要求的最短路的路径,就是一个欧拉图。所以定义无向图的所有边只能走一次。走两次的道路就有两条边了(一条建图是本来就有,另一条就添进去)。这样最短路就可以在原图的基础上添边构成了。
添的边表示这条路走了两次。对于怎么添边:为了构成一个欧拉图的,就得要消除图中的奇度顶点,要么两个奇度顶点之间连,要么两个奇度顶点连在同一个偶度顶点上(这两个条件可以用floyed算法处理)。用二进制0或1,来表示这个奇度点是否解决。搜索枚举所有的奇度顶点两两组合的情况。枚举的最小值加上原图的权值就是最短路的值。
#include <stdio.h>
#include <string.h>
#define Maxsize 20
#define FindMin(a,b) a>b?b:a
#define INF 999999999
int g[Maxsize][Maxsize];
int degree[Maxsize];
int count;
int v[Maxsize];
int ans;
int T;
void dfs(int u,int value)
{
int i,j;
if(u==T)
{
ans=FindMin(value,ans);
// printf("%d %d\n",value);
}
for(i=0;i<count;i++)
{
if(!((u>>i)&1))
{
for(j=i+1;j<count;j++)
if(!((u>>j)&1))
{
int next=u;
next=next|(1<<i);
next=next|(1<<j);
dfs(next,value+g[v[i]][v[j]]);
}
}
}
}
int main()
{
int n,m;
int u,e,l;
int i,j,k;
int sum=0;
while(~scanf("%d%d",&n,&m))
{
memset(degree,0,sizeof(degree));
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
g[i][j]=INF;
sum=0;
while(m--)
{
scanf("%d%d%d",&u,&e,&l);
sum+=l;
degree[u]++;degree[e]++;
g[u][e]=g[e][u]=FindMin(g[u][e],l);
}
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
g[i][j]=FindMin(g[i][j],g[i][k]+g[k][j]);
count=0;
for(i=1;i<=n;i++)
if(degree[i]&1)
v[count++]=i;
T=0;
for(i=0;i<count;i++)
{
T=(T<<1)|1;
}
ans=INF;
dfs(0,0);
printf("%d\n",sum+ans);
}
return 0;
}