这题可以看成在图上加一些边使得这张图有欧拉回路。先用弗洛伊德算法算出在i和j之间加一条边的代价。然后定义状态st表示,若st的第i位为1,那么当前i点的度数为奇数。所以找到原图开始的状态s,每次枚举两个点,在这两个点之间加一条边,转移到一个新的状态。数据规模不大,我们可以枚举所有的转移。跑一边spfa就可以了,答案是第d[0]。
#include <bits/stdc++.h>
#define maxn 100
using namespace std;
int d[maxn][maxn],n,m,du[maxn];
int dis[1<<16],inq[1<<16];
const int INF=1e9;
void spfa(int s)
{
for(int i=0;i<1<<n;i++)
dis[i]=INF;
dis[s]=0;
queue<int>Q;
Q.push(s);
while(!Q.empty())
{
int u=Q.front();
Q.pop();
inq[u]=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(dis[u^(1<<i)^(1<<j)]>dis[u]+d[i][j])
{
dis[u^(1<<i)^(1<<j)]=dis[u]+d[i][j];
if(!inq[u^(1<<i)^(1<<j)])
{
inq[u^(1<<i)^(1<<j)]=1;
Q.push(u^(1<<i)^(1<<j));
}
}
}
}
}
}
int main()
{
int ans=0;
scanf("%d%d",&n,&m);
int x,y,z,st=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i==j)
d[i][j]=0;
else
d[i][j]=INF;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
x--;y--;
d[x][y]=min(d[x][y],z);
d[y][x]=min(d[y][x],z);
du[x]++;du[y]++;
st^=(1<<x);
st^=(1<<y);
ans+=z;
}
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
for(int i=0;i<n;i++)
{
if(du[i])
{
if(d[0][i]==INF)
{
printf("-1");
return 0;
}
}
}
spfa(st);
ans+=dis[0];
printf("%d\n",ans);
//system("pause");
return 0;
}