在一个无向图中..从某点出发..每个边正好经过一次可以回到自己..必要条件是所有点的度为偶数..也就在一个无向图中存在欧拉回路的必要条件...注意..是必要条件...比如说...图是不连通的...
对应本题....题目是说从点1出发边可以经过任意多次..遍历完所有的边..回到点1的最短距离..一看N<=15...状态压缩DP..但怎么设置状态呢?...看一种特殊的情况..若是点1可以到达所有点..并且所有点的度为偶数..问题不就和欧拉回路相同么...所有边长度之和就是答案..但是题目中有度为奇数的点..就不得不多走一些路...让有些边经过不止一次..这些多走的边可以看成多加的边..比如样例2..3走回1..可以看做3到1加了一条长度为7的边...
问题转换..最短要加多长的若干边..使得这个无向图成为一个满足欧拉回路的图...
先用floyd找出任意两点的最短路径...作为加边的预处理...然后枚举所有的奇数度点...看怎么加边方案最优...枚举这个感觉太麻烦..不如用状态dp来做这个过程...状态k代表其为1的点度都是偶的需要加最短长度的边...由于要加边必定是加在两个度为奇的点上...所以对于一个状态..枚举其为0代表的两个奇数度点..进行更新..
Program:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<algorithm>
#define ll long long
#define oo 1000000007
#define pi acos(-1.0)
#define MAXN 16
using namespace std;
int n,sum,dp[1<<MAXN],arc[MAXN][MAXN],d[MAXN];
void Floyd()
{
int k,i,j;
for (k=0;k<n;k++)
for (i=0;i<n;i++)
for (j=0;j<n;j++)
arc[i][j]=min(arc[i][j],arc[i][k]+arc[k][j]);
}
int getans()
{
int i,j,x,t,totol;
Floyd();
for (i=1;i<n;i++)
if (d[i] && arc[0][i]>oo) return -1;
memset(dp,0x7f,sizeof(dp));
dp[0]=0;
totol=(1<<n)-1;
for (t=0;t<=totol;t++)
{
for (i=0;i<n;i++)
if (d[i]%2 && (t & (1<<i))) break;
if (i==n) dp[t]=0; //该状态不含奇数度点
for (i=0;i<n;i++)
if (d[i]%2 && !(t & (1<<i))) // 枚举奇数度点i
for (j=i+1;j<n;j++)
if (d[j]%2 && !(t & (1<<j)) && arc[i][j]<oo) // 枚举奇数度点j
dp[t|(1<<i)|(1<<j)]=min(dp[t|(1<<i)|(1<<j)],dp[t]+arc[i][j]);
}
if (dp[totol]>oo) return -1;
return sum+dp[totol];
}
int main()
{
int m;
while (~scanf("%d%d",&n,&m))
{
sum=0;
memset(arc,0x3f,sizeof(arc));
memset(d,0,sizeof(d));
for (int i=1;i<=m;i++)
{
int x,y,l;
scanf("%d%d%d",&x,&y,&l);
sum+=l;
x--,y--;
arc[y][x]=arc[x][y]=min(arc[x][y],l);
d[x]++,d[y]++;
}
printf("%d\n",getans());
}
return 0;
}