CodeForces 21 D Traveling Graph
原创
©著作权归作者所有:来自51CTO博客作者qq636b7aec0b3f1的原创作品,请联系作者获取转载授权,否则将追究法律责任
Description
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).
Input
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 wis the edge length.
Output
Output minimal cycle length or -1
Sample Input
Input
Output
3
Input
Output
14
要求是每条边至少走一遍的最小花费,先转变为一个欧拉回路问题,即在奇数度的节点上加边使其变为偶数,所有点都为偶数度即有欧拉回路,然后是加边操作,先用floyd预处理出最短路即可。需要注意判断是否可以走遍所有边。
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
typedef long long LL;
const int low(int x) { return x&-x; }
const int INF = 0x7FFFFFFF;
const int maxn = 20;
int T, n, m, ans, x, y, z;
int dis[maxn][maxn], cnt[maxn], fa[maxn];
int a[maxn], tot, vis[maxn];
int get(int x)
{
return x == fa[x] ? x : fa[x] = get(fa[x]);
}
int dfs()
{
for (int i = 0; i < tot; i++)
{
if (vis[i]) continue;
int ans = INF;
for (int j = i + 1; j < tot; j++)
{
if (vis[j]) continue;
vis[i] = vis[j] = 1;
ans = min(ans, dis[a[i]][a[j]] + dfs());
vis[i] = vis[j] = 0;
}
return ans;
}
return 0;
}
int main()
{
while (~scanf("%d%d", &n, &m))
{
ans = 0;
for (int i = 1; i <= n; i++)
{
cnt[i] = 0; fa[i] = i;
for (int j = 1; j <= n; j++) dis[i][j] = INF;
}
int flag1 = 0, flag2 = 0;
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d", &x, &y, &z);
ans += z;
if (++cnt[x] == 1) flag2++;
if (++cnt[y] == 1) flag2++;
int fx = get(x), fy = get(y);
if (fx != fy) { fa[fx] = fy; flag1++; }
dis[x][y] = min(dis[x][y], z);
dis[y][x] = min(dis[y][x], z);
}
if (n == 1 || m == 0) { printf("%d\n", ans); continue; }
if (flag1 + 1 != flag2 || cnt[1] == 0) { printf("-1\n"); continue; }
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
if (k == i || dis[i][k] == INF) continue;
for (int j = 1; j <= n; j++)
{
if (j == i || j == k) continue;
if (dis[k][j] == INF) continue;
if (dis[i][j] > dis[i][k] + dis[k][j])
{
dis[i][j] = dis[i][k] + dis[k][j];
}
}
}
}
tot = 0;
for (int i = 1; i <= n; i++)
{
if (cnt[i] & 1)
{
vis[tot] = 0;
a[tot++] = i;
}
}
printf("%d\n", ans + dfs());
}
return 0;
}