【题意】:给出一副无向图,n个点m条边,每条边上都有一个权值,表示通过这条边的费用。现在问任选一个点i开始遍历完所有边至少一次回到i的最小费用是多少。

【题解】:先累加一次所有边的费用sum,然后保留奇度的点,对于每两个奇度的点连边,费用为点到点的最短距离,求一次最小匹配res。最后答案为sum+res。
              对于用km求最小匹配,把边权取反再加上一个inf,最后减回去即可,没边的权值为0。

【代码】:
  1 #include "iostream"
  2 #include "cstdio"
  3 #include "cstring"
  4 #include "algorithm"
  5 #include "vector"
  6 #include "queue"
  7 #include "cmath"
  8 #include "string"
  9 #include "cctype"
 10 #include "map"
 11 #include "iomanip"
 12 #include "set"
 13 #include "utility"
 14 using namespace std;
 15 typedef pair<intint> pii;
 16 #define pb push_back
 17 #define mp make_pair
 18 #define fi first
 19 #define se second
 20 #define sof(x) sizeof(x)
 21 #define lc(x) (x << 1)
 22 #define rc(x) (x << 1 | 1)
 23 #define lowbit(x) (x & (-x))
 24 #define ll long long
 25 #define MAX 110
 26 #define maxn 110
 27 int n, m;
 28 const int inf = 100000000;
 29 int g[MAX][MAX];
 30 
 31 int d[MAX];
 32 int maz[maxn][maxn], lx[maxn], ly[maxn], match[maxn], sy[maxn], slack[maxn], sx[maxn];
 33 int nx, ny;
 34 int q[maxn], tot;
 35 bool dfs(int t) {
 36     sx[t] = 1;
 37     for (int i = 1; i <= ny; ++i) {
 38         if (sy[i])continue;
 39         if (maz[t][i] == lx[t] + ly[i]) {
 40             sy[i] = 1;
 41             if (match[i] == -1 || dfs(match[i])) {
 42                 match[i] = t;
 43                 return 1;
 44             }
 45         } else slack[i] = min(slack[i], lx[t] + ly[i] - maz[t][i]);
 46     }
 47     return 0;
 48 }
 49 void Change() {
 50     int Min = inf;
 51     for (int i = 1; i <= ny; ++i)
 52         if (!sy[i]) Min = min(Min, slack[i]);
 53     for (int i = 1; i <= nx; ++i)
 54         if (sx[i]) lx[i] -= Min;
 55     for (int i = 1; i <= ny; ++i) {
 56         if (sy[i]) ly[i] += Min;
 57         else slack[i] -= Min;
 58     }
 59 }
 60 int KM() {
 61     int ans = 0;
 62     memset(match, -1, sizeof (match));
 63     for (int i = 1; i <= nx; ++i) {
 64         for (int j = 1; j <= ny; ++j)
 65             slack[j] = inf;
 66         while (1) {
 67             memset(sy, 0, sizeof (sy));
 68             memset(sx, 0, sizeof (sx));
 69             if (dfs(i)) break;
 70             Change();
 71         }
 72     }
 73     for (int i = 1; i <= ny; ++i)
 74         if(match[i] != -1) ans += inf - maz[match[i]][i];
 75     return ans / 2;
 76 }
 77 void build() {
 78     memset(maz, 0, sizeof (maz));
 79     nx = tot;
 80     ny = tot;
 81     for(int i = 0; i < tot; i++)
 82         for(int j = 0; j < tot; j++) {
 83             if(i != j) maz[i+1][j+1] = inf - g[q[i]][q[j]];
 84         }
 85     memset(ly, 0, sizeof (ly));
 86     for (int i = 1; i <= nx; ++i) {
 87         lx[i] = -inf;
 88         for (int j = 1; j <= ny; ++j)
 89             lx[i] = max(lx[i], maz[i][j]);
 90     }
 91 }
 92 
 93 int floyd() {
 94     for(int k = 1; k <= n; k++)
 95         for(int i = 1; i <= n; i++)
 96             for(int j = 1; j <= n; j++)
 97                 g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
 98 }
 99 
100 int main() {
101     int T, x;
102     scanf("%d", &T);
103     while(T--) {
104         scanf("%d%d", &n, &m);
105         for(int i = 1; i <= n; i++) {
106             for(int j = 1; j <= n; j++)
107                 g[i][j] = inf;
108             g[i][i] = 0;
109         }
110         int ans = 0;
111         memset(d, 0, sizeof(d));
112         for(int i = 0; i < m; i++) {
113             int u, v, w;
114             scanf("%d%d%d", &u, &v, &w);
115             ans += w;
116             g[u][v] = g[v][u] = w;
117             d[u]++, d[v]++;
118         }
119         tot = 0;
120         for(int i = 1; i <= n; i++)
121             if(d[i] & 1) q[tot++] = i;
122         floyd();
123         build();
124         int res = KM();
125         cout << ans + res << endl;
126         scanf("%d", &x);
127         if(x == -1) break;
128     }
129 
130     return 0;
131 }
132