Given an integer n representing the number of vertices in an undirected weighted graph and an array edges[][] of sizem, where edges[i] = [u, v, w] represents an edge between vertices u and v with weight w.
Find the minimum cost of a closed walk that starts and ends at the same vertex and visits every edge at least once.
Return -1 if it is not possible to visit every edge in a single closed walk.
Output: 10 Explanation: The vertices 3 and 4 have odd degree, so the edge between them must be traversed one additional time. The minimum total cost is 8 + 2 = 10.
Minimum Cost Eulerian Tour Using Floyd-Warshall with Bitmask DP
The idea is to convert the graph into a Eulerian Graph with the minimum possible extra cost.
Since a closed walk is a Eulerian circuit it requires every vertex to have an even degree, hence we identify the odd-degree vertices and pair them up.
For each pair, we repeat the shortest path between them, which makes both vertices even. Finally we take the minimum-cost way to pair all odd-degree vertices.
Problem arises when the graph is not eulerian, i.e. some vertices have an odd degree.
What what if the two vertices with odd degree are not neighbours?
We can repeat a whole path instead of a single edge.
Every vertex in the middle of the path gets +2 (once in, once out), so its parity is unchanged. Only the two endpoints flip.
So pairing two odd degree vertices (u, v) gives us extra cost = shortest distance (u, v).
We need shortest distances between every pair of odd degree vertices, so we precompute all-pairs shortest paths using the Floyd Warshall's Algorithm.
Now the remaining part of the problem is minimising the extra cost required to make the graph eulerian.
Every edge must be visited at least once, so the sum of all edge weights is always part of the cost.
Every vertex has even degree. For an odd-degree vertex, we need to duplicate some edges to flip its parity.
Duplicating a path u -> ... -> v adds 2 to every internal vertex and 1 to each endpoint. Thus, only u and v change parity.
Therefore, duplicating a path between two odd-degree vertices makes both even.
Hence, all odd-degree vertices must be paired, with each pair connected by a duplicated path. We want the pairing and paths with minimum total cost.
At this point we have 2 level of choices
What path to use for a pair of odd degree vertices (u, v)? The shortest path between them.
Which vertices do we pair together? Every pairing makes all degrees even, but they do not all cost the same, so we need the one with the smallest total.
To achieve this we use bitmask DP
Let k be the number of odd-degree vertices. We use a k-bit mask to represent which odd vertices have already been paired.
For k = 4, 0000 means no odd degree vertices are paired, 0011 means 1 and 2 odd degree vertices are paired, 0101 means 1 and 3 odd degree vertices are paired.
Define dp[mask] as the minimum cost required to pair all odd vertices whose bits are 1. For example, dp[0101] represents the minimum cost of pairing odd degree vertices 1 and 3.
The same mask can be reached through different pairings. For example, 1111 can be reached by pairing (1,2) and (3,4), or by pairing (1,3) and (2,4). This creates overlapping sub-problems.
From a given mask, find the first unpaired odd vertex i, i.e. the first bit that is 0.
Pair i with every other unpaired vertex j and mark both as paired. The new state is newMask = mask | (1 << i) | (1 << j), with an additional cost of dist[odd[i]][odd[j]].
Take the minimum cost among all possible choices of j. This explores every possible pairing while storing only the cheapest cost for each state.
Finally:
Build the adjacency information, the degree array, and totalCost.
Check that all vertices with edges are connected (BFS). If not, return -1.
Run Floyd-Warshall to get shortest distances between all pairs.
Collect the odd-degree vertices. If there are none, return totalCost.
Run the bitmask DP over the odd vertices.
Return totalCost + dp[(1 << k) - 1].
Consider the following example: n = 5, edges = [[1,2,2], [2,3,1], [3,4,1], [4,5,2], [2,4,1]]
C++
#include<bits/stdc++.h>usingnamespacestd;intpairCost(intmask,vector<int>&odd,vector<vector<int>>&dist,vector<int>&dp){intk=odd.size();if(mask==(1<<k)-1)return0;if(dp[mask]!=-1)returndp[mask];intfirst=0;while(mask&(1<<first))first++;intans=INT_MAX;// Pair the first unpaired odd-degree vertex with every other unpaired vertex.for(intj=first+1;j<k;j++){if(!(mask&(1<<j))){intnewMask=mask|(1<<first)|(1<<j);intcost=dist[odd[first]][odd[j]]+pairCost(newMask,odd,dist,dp);ans=min(ans,cost);}}returndp[mask]=ans;}intminTourCost(intn,vector<vector<int>>&edges){constintINF=1e9;vector<vector<int>>dist(n,vector<int>(n,INF));vector<vector<int>>adj(n);vector<int>degree(n,0);inttotalCost=0;// Initialize distance from every vertex to itself as zero.for(inti=0;i<n;i++)dist[i][i]=0;// Build the graph, calculate degrees, and store the total edge cost.for(auto&edge:edges){intu=edge[0]-1;intv=edge[1]-1;intw=edge[2];dist[u][v]=min(dist[u][v],w);dist[v][u]=min(dist[v][u],w);adj[u].push_back(v);adj[v].push_back(u);degree[u]++;degree[v]++;totalCost+=w;}// Find a vertex that is incident to at least one edge.intstart=-1;for(inti=0;i<n;i++){if(degree[i]>0){start=i;break;}}if(start==-1)return0;// Check that all vertices with edges belong to the same component.vector<bool>visited(n,false);queue<int>q;q.push(start);visited[start]=true;while(!q.empty()){intu=q.front();q.pop();for(intv:adj[u]){if(!visited[v]){visited[v]=true;q.push(v);}}}for(inti=0;i<n;i++){if(degree[i]>0&&!visited[i])return-1;}// Compute the shortest distance between every pair of vertices.for(intk=0;k<n;k++){for(inti=0;i<n;i++){for(intj=0;j<n;j++){if(dist[i][k]<INF&&dist[k][j]<INF){dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);}}}}vector<int>odd;// Collect all vertices having odd degree.for(inti=0;i<n;i++){if(degree[i]%2==1)odd.push_back(i);}intk=odd.size();if(k==0)returntotalCost;vector<int>dp(1<<k,-1);// Find the minimum additional cost required to pair all odd vertices.intextraCost=pairCost(0,odd,dist,dp);returntotalCost+extraCost;}intmain(){intn=4;vector<vector<int>>edges={{1,2,2},{2,3,3},{3,1,1},{3,4,2}};cout<<minTourCost(n,edges)<<'\n';return0;}
Java
importjava.util.*;classGFG{staticintpairCost(intmask,int[]odd,int[][]dist,int[]dp){intk=odd.length;if(mask==(1<<k)-1)return0;if(dp[mask]!=-1)returndp[mask];intfirst=0;while((mask&(1<<first))!=0)first++;intans=Integer.MAX_VALUE;// Pair the first unpaired odd-degree vertex with// every other unpaired vertex.for(intj=first+1;j<k;j++){if((mask&(1<<j))==0){intnewMask=mask|(1<<first)|(1<<j);intcost=dist[odd[first]][odd[j]]+pairCost(newMask,odd,dist,dp);ans=Math.min(ans,cost);}}returndp[mask]=ans;}staticintminTourCost(intn,int[][]edges){finalintINF=1000000000;int[][]dist=newint[n][n];int[]degree=newint[n];ArrayList<Integer>[]adj=newArrayList[n];for(inti=0;i<n;i++){Arrays.fill(dist[i],INF);dist[i][i]=0;adj[i]=newArrayList<>();}inttotalCost=0;// Build the graph, calculate degrees, and store the// total edge cost.for(int[]edge:edges){intu=edge[0]-1;intv=edge[1]-1;intw=edge[2];dist[u][v]=Math.min(dist[u][v],w);dist[v][u]=Math.min(dist[v][u],w);adj[u].add(v);adj[v].add(u);degree[u]++;degree[v]++;totalCost+=w;}// Find a vertex that is incident to at least one// edge.intstart=-1;for(inti=0;i<n;i++){if(degree[i]>0){start=i;break;}}if(start==-1)return0;// Check that all vertices with edges belong to the// same component.boolean[]visited=newboolean[n];Queue<Integer>q=newLinkedList<>();q.add(start);visited[start]=true;while(!q.isEmpty()){intu=q.poll();for(intv:adj[u]){if(!visited[v]){visited[v]=true;q.add(v);}}}for(inti=0;i<n;i++){if(degree[i]>0&&!visited[i])return-1;}// Compute the shortest distance between every pair// of vertices.for(intk=0;k<n;k++){for(inti=0;i<n;i++){for(intj=0;j<n;j++){if(dist[i][k]<INF&&dist[k][j]<INF){dist[i][j]=Math.min(dist[i][j],dist[i][k]+dist[k][j]);}}}}ArrayList<Integer>oddList=newArrayList<>();// Collect all vertices having odd degree.for(inti=0;i<n;i++){if(degree[i]%2==1)oddList.add(i);}intk=oddList.size();int[]odd=newint[k];for(inti=0;i<k;i++)odd[i]=oddList.get(i);if(k==0)returntotalCost;int[]dp=newint[1<<k];Arrays.fill(dp,-1);// Find the minimum additional cost required to pair// all odd vertices.intextraCost=pairCost(0,odd,dist,dp);returntotalCost+extraCost;}publicstaticvoidmain(String[]args){intn=4;int[][]edges={{1,2,2},{2,3,3},{3,1,1},{3,4,2}};System.out.println(minTourCost(n,edges));}}
Python
fromcollectionsimportdequedefpairCost(mask,odd,dist,dp):k=len(odd)ifmask==(1<<k)-1:return0ifdp[mask]!=-1:returndp[mask]first=0whilemask&(1<<first):first+=1ans=float('inf')# Pair the first unpaired odd-degree vertex with every other unpaired vertex.forjinrange(first+1,k):ifnot(mask&(1<<j)):newMask=mask|(1<<first)|(1<<j)cost=dist[odd[first]][odd[j]]+pairCost(newMask,odd,dist,dp)ans=min(ans,cost)dp[mask]=ansreturnansdefminTourCost(n,edges):INF=10**9dist=[[INF]*nfor_inrange(n)]degree=[0]*nadj=[[]for_inrange(n)]totalCost=0# Initialize distance from every vertex to itself as zero.foriinrange(n):dist[i][i]=0# Build the graph, calculate degrees, and store the total edge cost.foredgeinedges:u=edge[0]-1v=edge[1]-1w=edge[2]dist[u][v]=min(dist[u][v],w)dist[v][u]=min(dist[v][u],w)adj[u].append(v)adj[v].append(u)degree[u]+=1degree[v]+=1totalCost+=w# Find a vertex that is incident to at least one edge.start=-1foriinrange(n):ifdegree[i]>0:start=ibreakifstart==-1:return0# Check that all vertices with edges belong to the same component.visited=[False]*nq=deque([start])visited[start]=Truewhileq:u=q.popleft()forvinadj[u]:ifnotvisited[v]:visited[v]=Trueq.append(v)foriinrange(n):ifdegree[i]>0andnotvisited[i]:return-1# Compute the shortest distance between every pair of vertices.forkinrange(n):foriinrange(n):forjinrange(n):ifdist[i][k]<INFanddist[k][j]<INF:dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j])odd=[]# Collect all vertices having odd degree.foriinrange(n):ifdegree[i]%2==1:odd.append(i)k=len(odd)ifk==0:returntotalCostdp=[-1]*(1<<k)# Find the minimum additional cost required to pair all odd vertices.extraCost=pairCost(0,odd,dist,dp)returntotalCost+extraCostif__name__=="__main__":n=4edges=[[1,2,2],[2,3,3],[3,1,1],[3,4,2]]print(minTourCost(n,edges))
C#
usingSystem;usingSystem.Collections.Generic;classGFG{staticintpairCost(intmask,int[]odd,int[][]dist,int[]dp){intk=odd.Length;if(mask==(1<<k)-1)return0;if(dp[mask]!=-1)returndp[mask];intfirst=0;while((mask&(1<<first))!=0)first++;intans=int.MaxValue;// Pair the first unpaired odd-degree vertex with// every other unpaired vertex.for(intj=first+1;j<k;j++){if((mask&(1<<j))==0){intnewMask=mask|(1<<first)|(1<<j);intcost=dist[odd[first]][odd[j]]+pairCost(newMask,odd,dist,dp);ans=Math.Min(ans,cost);}}returndp[mask]=ans;}staticintminTourCost(intn,int[][]edges){constintINF=1000000000;int[][]dist=newint[n][];int[]degree=newint[n];List<int>[]adj=newList<int>[n];for(inti=0;i<n;i++){dist[i]=newint[n];Array.Fill(dist[i],INF);dist[i][i]=0;adj[i]=newList<int>();}inttotalCost=0;// Build the graph, calculate degrees, and store the// total edge cost.foreach(int[]edgeinedges){intu=edge[0]-1;intv=edge[1]-1;intw=edge[2];dist[u][v]=Math.Min(dist[u][v],w);dist[v][u]=Math.Min(dist[v][u],w);adj[u].Add(v);adj[v].Add(u);degree[u]++;degree[v]++;totalCost+=w;}// Find a vertex that is incident to at least one// edge.intstart=-1;for(inti=0;i<n;i++){if(degree[i]>0){start=i;break;}}if(start==-1)return0;// Check that all vertices with edges belong to the// same component.bool[]visited=newbool[n];Queue<int>q=newQueue<int>();q.Enqueue(start);visited[start]=true;while(q.Count>0){intu=q.Dequeue();foreach(intvinadj[u]){if(!visited[v]){visited[v]=true;q.Enqueue(v);}}}for(inti=0;i<n;i++){if(degree[i]>0&&!visited[i])return-1;}// Compute the shortest distance between every pair// of vertices.for(intmid=0;mid<n;mid++){for(inti=0;i<n;i++){for(intj=0;j<n;j++){if(dist[i][mid]<INF&&dist[mid][j]<INF){dist[i][j]=Math.Min(dist[i][j],dist[i][mid]+dist[mid][j]);}}}}List<int>oddList=newList<int>();// Collect all vertices having odd degree.for(inti=0;i<n;i++){if(degree[i]%2==1)oddList.Add(i);}intk=oddList.Count;int[]odd=newint[k];for(inti=0;i<k;i++)odd[i]=oddList[i];if(k==0)returntotalCost;int[]dp=newint[1<<k];Array.Fill(dp,-1);// Find the minimum additional cost required to pair// all odd vertices.intextraCost=pairCost(0,odd,dist,dp);returntotalCost+extraCost;}publicstaticvoidMain(){intn=4;int[][]edges={newint[]{1,2,2},newint[]{2,3,3},newint[]{3,1,1},newint[]{3,4,2}};Console.WriteLine(minTourCost(n,edges));}}
JavaScript
functionpairCost(mask,odd,dist,dp){constk=odd.length;if(mask===(1<<k)-1)return0;if(dp[mask]!==-1)returndp[mask];letfirst=0;while(mask&(1<<first))first++;letans=Infinity;// Pair the first unpaired odd-degree vertex with every// other unpaired vertex.for(letj=first+1;j<k;j++){if(!(mask&(1<<j))){constnewMask=mask|(1<<first)|(1<<j);constcost=dist[odd[first]][odd[j]]+pairCost(newMask,odd,dist,dp);ans=Math.min(ans,cost);}}dp[mask]=ans;returnans;}functionminTourCost(n,edges){constINF=1e9;constdist=Array.from({length:n},()=>Array(n).fill(INF));constdegree=Array(n).fill(0);constadj=Array.from({length:n},()=>[]);lettotalCost=0;// Initialize distance from every vertex to itself as// zero.for(leti=0;i<n;i++)dist[i][i]=0;// Build the graph, calculate degrees, and store the// total edge cost.for(constedgeofedges){constu=edge[0]-1;constv=edge[1]-1;constw=edge[2];dist[u][v]=Math.min(dist[u][v],w);dist[v][u]=Math.min(dist[v][u],w);adj[u].push(v);adj[v].push(u);degree[u]++;degree[v]++;totalCost+=w;}// Find a vertex that is incident to at least one edge.letstart=-1;for(leti=0;i<n;i++){if(degree[i]>0){start=i;break;}}if(start===-1)return0;// Check that all vertices with edges belong to the same// component.constvisited=Array(n).fill(false);constqueue=[start];visited[start]=true;letfront=0;while(front<queue.length){constu=queue[front++];for(constvofadj[u]){if(!visited[v]){visited[v]=true;queue.push(v);}}}for(leti=0;i<n;i++){if(degree[i]>0&&!visited[i])return-1;}// Compute the shortest distance between every pair of// vertices.for(letk=0;k<n;k++){for(leti=0;i<n;i++){for(letj=0;j<n;j++){if(dist[i][k]<INF&&dist[k][j]<INF){dist[i][j]=Math.min(dist[i][j],dist[i][k]+dist[k][j]);}}}}constodd=[];// Collect all vertices having odd degree.for(leti=0;i<n;i++){if(degree[i]%2===1)odd.push(i);}constk=odd.length;if(k===0)returntotalCost;constdp=Array(1<<k).fill(-1);// Find the minimum additional cost required to pair all// odd vertices.constextraCost=pairCost(0,odd,dist,dp);returntotalCost+extraCost;}// Driver Codeconstn=4;constedges=[[1,2,2],[2,3,3],[3,1,1],[3,4,2]];console.log(minTourCost(n,edges));
Output
10
Time Complexity: O(n^3 + 2^k * k^2)
Floyd-Warshall takes O(n^3).
Bitmask DP has 2^k states where k is the number of vertices with odd degree, and each state can try up to O(k^2) pairings.