HDU 6311 Cover & 2018杭电多校第二场1003

题目:HDU 6311 Cover

题意:给定一幅简单图(无重边无自环),问一笔画(边不能重复走)最少要几笔?并且输出路径

思路:很明显,在一个联通块之中若是奇度数的节点少于等于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;
}

猜你喜欢

转载自blog.csdn.net/weixin_38287798/article/details/81236219
今日推荐