2018 Multi-University Training Contest 2 1003 Cover 图论 欧拉通路

题目链接: 1003 Cover

题目大意

一张无向图,n个节点,m条边,没有重边和自环,不一定连通,求最少多少条路径能覆盖这张图所有边,每条边只能被一条路径覆盖

思路

将图中每个联通块的奇点(度数为奇数的点)找出来,如果有两个或两个以下的奇点,可以一笔画,否则从第三个奇点开始,将奇点们两两连接起来,让这张图有欧拉通路,求其欧拉通路,将后来新增的奇点连边删除后,得到的路径就是覆盖这个联通块所有边需要的最小路径数

代码

6311 1060MS 19164K 2465 B G++

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;
const int maxn = 1e5 + 100, mod = 1e9 + 7, inf = 0x3f3f3f3f;
typedef pair<int, int> P;
typedef long long ll;
int n, m;
struct edge
{
    int to, nxt;
    edge(int t = 0, int n = 0) : to(t), nxt(n) {}
};
edge es[maxn * 3];
int head[maxn * 3];
int d[maxn];

void addedge(int id, int u, int v)
{
    es[id * 2] = edge(v, head[u]);
    head[u] = id * 2;
    es[id * 2 + 1] = edge(u, head[v]);
    head[v] = id * 2 + 1;
}
vector<int> odd;
int cnt_path;
vector<int> path[maxn];

bool vist_node[maxn];
void find_odd(int u)
{
    vist_node[u] = 1;
    if (d[u] & 1) odd.push_back(u);
    for (int i = head[u]; i; i = es[i].nxt)
    {
        int v = es[i].to;
        if (vist_node[v]) continue;
        find_odd(es[i].to);
    }
}

bool vist_edge[maxn * 3];
void dfs(int u)
{
    for (int i = head[u]; i; i = es[i].nxt)
    {
        int v = es[i].to;
        if (vist_edge[i / 2]) continue;
        vist_edge[i / 2] = 1;
        dfs(v);//先dfs再记录路径, 遇到桥的时候即使先走了桥也能记录一条完整的路径
        if (i / 2 > m) ++cnt_path;
        else path[cnt_path].push_back(i / 2 * ((i & 1) ? 1 : -1));
    }
}

int main()
{
    while (scanf("%d%d", &n, &m) == 2)
    {
        int u, v;
        memset(d, 0, sizeof(d));
        memset(head, 0, sizeof(head));
        memset(vist_node, 0, sizeof(vist_node));
        memset(vist_edge, 0, sizeof(vist_edge));

        for (int i = 1; i <= m; ++i)
        {
            scanf("%d%d", &u, &v);
            addedge(i, u, v);
            ++d[u];
            ++d[v];
        }
        int id = m + 1;
        for (int i = 1; i <= n; ++i)
        {
            if (!vist_node[i] && d[i])
            {
                find_odd(i);
                if (odd.size() == 0) odd.push_back(i);
                for (int j = 2; j < (int)odd.size(); j += 2) //
                    addedge(id++, odd[j], odd[j + 1]);
                ++cnt_path;
                dfs(odd[0]);
                odd.clear();
            }
        }
        printf("%d\n", cnt_path);
        for (int i = 1; i <= cnt_path; ++i)
        {
            printf("%d", (int)path[i].size());
            for (int ite : path[i]) printf(" %d", ite);
            printf("\n");
        }
        for (int i = 1; i <= cnt_path; ++i) path[i].clear();
        cnt_path = 0;

    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/litmxs/article/details/81214698
今日推荐