题意:给定一幅简单图(无重边无自环),问一笔画(边不能重复走)最少要几笔?并且输出路径
思路:很明显,在一个联通块之中若是奇度数的节点少于等于2个,那么就可以一笔画完(也就是欧拉回路的判断条件),但是一幅图可以存在多个奇度数节点,因而我们需要减少奇度数节点的个数——通过给奇度数的节点间加一条边的方式,每两个奇度数节点就添加了一条边,最后使得奇度数节点个数为0,然后直接跑一遍dfs就能够得到路径(回路)了。
路径中或存在着新添加的边,将其删去之后,一条回路就变成了一段一段的路径,这些路径就是一笔画的路径和个数,因此笔画数也就是max(1,奇度数节点个数/2)
注意:需要在意的是孤立节点,不能算作答案里面
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m;
struct node
{
int to, next, id;
}edge[N << 2];
int head[N], cnt;
int de[N];
int vis[N], used[N << 2];
vector<vector<int> > ans;
void init()
{
memset(head, -1, sizeof head);
memset(de, 0, sizeof de);
memset(used, 0, sizeof used);
memset(vis, 0, sizeof vis);
cnt = 0;
}
void add(int u, int v, int id)
{
edge[cnt] = node{v, head[u], id};
head[u] = cnt ++;
}
void dfs1(vector<int> &t, int u)
{//求联通块内的奇度数节点
vis[u] = 1;
if(de[u] & 1) t.push_back(u);
for(int i = head[u]; i + 1; i = edge[i].next)
{
int v = edge[i].to;
if(de[v] && !vis[v]) dfs1(t, v);
}
}
void dfs(vector<int> & t, int u)
{//求欧拉回路,保存路径
for(int i = head[u]; i + 1; i = edge[i].next)
{
if(!used[i])
{
int v = edge[i].to;
used[i] = used[i ^ 1] = 1;
de[u] --, de[v] --;
dfs(t, v);
t.push_back( -edge[i].id);
}
}
}
void solve()
{
ans.clear();
for(int i = 1; i <= n; i ++)
{
if(de[i] && !vis[i])
{
vector<int> t, q;
dfs1(t, i);
for(int j = 0; j < t.size(); j += 2)
{
int u = t[j], v = t[j + 1];
add(u, v, 0);//新添加的边id为0,正反向都无影响
add(v, u, 0);
de[u] ++, de[v] ++;
}
dfs(q, i);
if(t.size() == 0)
ans.push_back(q);
else
{
//如果这里的q是用deque保存的话,可以缩短一半以上的时间
while(*(q.end() - 1) != 0)
{
q.push_back(q[0]);
q.erase(q.begin());
}
t.clear();
for(int j = 0; j < q.size(); j ++)
{
if(q[j] == 0)
{
ans.push_back(t);
t.clear();
}
else
t.push_back(q[j]);
}
}
}
}
printf("%d\n", ans.size());
for(int i = 0; i < ans.size(); i ++)
{
printf("%d", ans[i].size());
for(int j = 0; j < ans[i].size(); j ++)
printf(" %d", ans[i][j]);
puts("");
}
}
int main()
{
while(~scanf("%d%d", &n, &m))
{
init();
for(int i = 1; i <= m; i ++)
{
int u, v;
scanf("%d%d", &u, &v);
de[u] ++; de[v] ++;
add(u, v, i);//正向边为+,反向边为-
add(v, u, -i);
}
solve();
}
return 0;
}