Cover
PS:最少路径覆盖。统计当前连通块中度数为奇数的顶点,然后留两个顶点作为DFS的起点和终点,其它的顶点每两个连一条虚边,使得度数为偶数个。据说有孤立的点;链式前向星的tot从1开始,并且第一条边的编号从2开始,,,,为了好计算边的序号(1 ~ m)。总之还是有编程技巧的。
#include "stdafx.h" #pragma warning(disable:4996) #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #define ll long long #define P pair<int, int> #define PP pair<int,pair<int, int>> #define pb push_back #define pp pop_back #define lson root << 1 #define INF (int)2e9 + 7 #define rson root << 1 | 1 #define LINF (unsigned long long int)1e18 #define mem(arry, in) memset(arry, in, sizeof(arry)) using namespace std; const int N = 100005; int n, m, tot, cnt; int head[4 * N], vis[4 * N], use[4 * N], deg[N]; vector<int> v, ans[N]; struct node { int to, next; } e[4 * N]; void Inite() { cnt = 0; tot = 1; mem(head, 0), mem(vis, 0), mem(use, 0), mem(deg, 0); } void addedge(int u, int v) { e[++tot].to = v; e[tot].next = head[u]; head[u] = tot; } void DFS(int u) { vis[u] = 1; if (deg[u] & 1) v.pb(u); for (int i = head[u]; i != 0; i = e[i].next) { int v = e[i].to; if (!vis[v]) DFS(v); } } // 搜索路径 void Find(int u) { for (int i = head[u]; i != 0; i = e[i].next) { int v = e[i].to; if (!use[i]) { use[i] = use[i ^ 1] = 1; Find(v); if (i > 2 * m + 1) cnt++; // 虚边,说明这是一条路径的起点 else { int tp = ((i & 1) == 1 ? i / 2 : -i / 2); ans[cnt].pb(tp); } } } } void Solve() { for (int i = 1; i <= n; i++) { if (!vis[i] && deg[i]) { DFS(i); int r = (int)v.size(); for (int j = 2; j < r; j += 2) { addedge(v[j], v[j + 1]); addedge(v[j + 1], v[j]); } cnt++; if (r) Find(v[0]); else Find(i); v.clear(); } } printf("%d\n", cnt); for (int i = 1; i <= cnt; i++) { int r = (int)ans[i].size(); printf("%d ", r); for (int j = 0; j < r; j++) { printf("%d%c", ans[i][j], (j + 1 == r ? '\n' : ' ')); } ans[i].clear(); } } int main() { while (scanf("%d %d", &n, &m) != EOF) { Inite(); for (int i = 1; i <= m; i++) { int u, v; scanf("%d %d", &u, &v); addedge(u, v); addedge(v, u); deg[u]++; deg[v]++; } Solve(); } return 0; }