You are given undirected weighted graph. Find the length of the shortest cycle which starts from the vertex 1 and passes throught all the edges at least once. Graph may contain multiply edges between a pair of vertices and loops (edges from the vertex to itself).
The first line of the input contains two integers n and m (1 ≤ n ≤ 15, 0 ≤ m ≤ 2000), n is the amount of vertices, and m is the amount of edges. Following m lines contain edges as a triples x, y, w (1 ≤ x, y ≤ n, 1 ≤ w ≤ 10000), x, y are edge endpoints, and w is the edge length.
Output minimal cycle length or -1 if it doesn't exists.
3 3 1 2 1 2 3 1 3 1 1
3
3 2 1 2 3 2 3 4
14
題意:
給出一個無向帶權圖,問從1號點出發,通過所有的邊至少一次,再回到1號點,需要花費的最少代價是多少。存在自環和重邊。
如果無法滿足上述要求,那麼輸出-1。
節點數n,邊數m。(1 <= n <= 15, 0 <= m <= 2000)
每條邊包含3個屬性u, v, w, u和v是邊的端點,w是通過邊的代價。(1 <= x,y <= n, 1 <= w <= 1e4)。
題解:
先跑一次Floyd求出全源最短路,如果1號點到某個點的最短路不存在那麼原圖不連通,
如果所有點的度數都是偶數,那麼存在一條歐拉回路,已經得到結果,
否則存在某些點的度數是奇數,嘗試用一些路徑連接這些點,只有路徑端點的度數奇偶性會發生變化,
可以發現度數已經是偶數的點作爲某條路徑的端點是不優的,於是考慮dp[S]表示度數是奇數的點集爲S時的最小代價,
轉移枚舉選出兩個集合內的點,用一條路連起來,這兩個點的度數都會變成偶數,複雜度是O(n^2*2^n),
一個trick是由於最後所有點度數都要是偶數,也就是每個度數是奇數的點都要作爲某條路徑的端點,
那麼每次考慮選出集合內標號最小的點,枚舉這個點和另一個點用一條路徑連起來,複雜度是O(n*2^n)。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const int inf=0x3fffffff;
const ll mod=1000000007;
const int maxn=18;
int g[maxn][maxn],d[1<<maxn];
int deg[maxn];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
rep(i,0,n) rep(j,0,n) g[i][j]=inf;
rep(i,0,n) g[i][i]=0;
int sum=0;
while(m--)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
u--,v--;
g[u][v]=min(g[u][v],w);
g[v][u]=min(g[v][u],w);
deg[u]++,deg[v]++;
sum+=w;
}
rep(k,0,n) rep(i,0,n) rep(j,0,n) g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
rep(i,1,n) if(deg[i]&&g[0][i]==inf) return 0*puts("-1");
int now=0;
rep(i,0,n) if(deg[i]&1) now|=(1<<i);
memset(d,0x3f,sizeof(d));
d[now]=0;
for(int j=now;j>0;j--)
{
for(int i=0;i<n;i++)
{
if(j&(1<<i))
{
for(int k=i+1;k<n;k++)
if(j&(1<<k))
d[j^(1<<i)^(1<<k)]=min(d[j^(1<<i)^(1<<k)],d[j]+g[i][k]);
}
}
}
printf("%d\n",sum+d[0]);
return 0;
}