HDU6311 Cover【欧拉路径 | 回路】

HDU6311 Cover

题意:

给出\(N\)个点的简单无向图,不一定联通,现在要用最少的路径去覆盖所有边,并且每条边只被覆盖一次,问最少路径覆盖数和各条路径
\(N\le 10^5\)

题解:

对于每个连通块分别处理
考虑每个联通块,必然是用最少的欧拉路径去覆盖,首先考虑连通块里没有奇数度数的点的情况,这个情况下只要跑欧拉回路即可
如果连通块中有\(x\)个奇数度数的点,那么显然\(2|x\),且必然是用\(\frac{x}{2}\)欧拉路径去覆盖,每两个奇数度数的顶点之间会有一条欧拉路径,考虑如何构造路径,首先将奇数度数的顶点两两配对连边,只剩下一对奇数度数点不连边,然后在新建的图中跑欧拉路径(此时必然存在欧拉路径),可以发现其中\(\frac{x}{2}-1\)条新加入的边正好把路径分成了\(\frac{x}{2}\)条,这些分开来的路径正好是所求路径

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e5+7;
int n, m, deg[MAXN], bel[MAXN], vis[MAXN<<2], num[MAXN];
vector<int> pt[MAXN];
struct Graph{
    int head[MAXN],to[MAXN<<2],nxt[MAXN<<2],tot,id[MAXN<<2];
    void clear(){ tot = 0; memset(head,255,MAXN<<2); }
    void addEdge(int u, int v, int idd){
        to[tot] = v; nxt[tot] = head[u]; id[tot] = idd;
        vis[tot] = false; head[u] = tot++;
        to[tot] = u; nxt[tot] = head[v]; id[tot] = -idd;
        vis[tot] = false; head[v] = tot++;
    }
}G;
void mark(int u, int id){
    bel[u] = id;
    pt[id].push_back(u);
    for(int i = G.head[u]; ~i; i = G.nxt[i]){
        int v = G.to[i];
        if(!bel[v]) mark(v,id);
    }
}
stack<int> stk;
void euler(int u){
    int now = ++num[u];
    for(int i = G.head[u]; ~i; i = G.nxt[i]){
        if(vis[i]) continue;
        G.head[u] = G.nxt[i];
        vis[i] = vis[i^1] = true;
        euler(G.to[i]);
        stk.push(G.id[i]);
        if(now!=num[u]) break;
    }
}
void print(){
    printf("%d ",stk.size());
    while(!stk.empty()){
        printf("%d%c",stk.top()," \n"[stk.size()==1]);
        stk.pop();
    }
}
void rua(int id){
    int odddeg = 0;
    for(int &x : pt[id]) if(deg[x]&1) odddeg++;
    if(!odddeg){
        euler(pt[id][0]);
        print();
    }
    else{
        int last = -1;
        for(int &x : pt[id]){
            if(odddeg==2) break;
            if(deg[x]&1){
                if(last==-1) last = x;
                else{
                    G.addEdge(last,x,0);
                    deg[last]++; deg[x]++;
                    last = -1;
                    odddeg -= 2;
                }
            }
        }
        for(int &x : pt[id]) if(deg[x]&1) last = x;
        euler(last);
        vector<int> vec;
        while(true){
            vec.clear();
            while(!stk.empty() and stk.top()!=0){
                vec.push_back(stk.top());
                stk.pop();
            }
            if(!stk.empty()) stk.pop();
            printf("%d",vec.size());
            for(int x : vec) printf(" %d",x);
            puts("");
            if(stk.empty()) break;
        }
    }
}
void solve(){
    G.clear();
    memset(deg+1,0,n<<2);
    for(int i = 1; i <= m; i++){
        int u, v; scanf("%d %d",&u,&v);
        G.addEdge(u,v,i);
        deg[u]++, deg[v]++;
    }
    int ID = 0;
    memset(bel+1,0,n<<2);
    int __count = 0;
    for(int i = 1; i <= n; i++) if(!bel[i]){
        pt[++ID].clear();
        mark(i,ID);
        if(pt[ID].size() > 1){
            int odddeg = 0;
            for(int x : pt[ID]) if(deg[x]&1) odddeg++;
            if(!odddeg) __count++;
            else __count += odddeg / 2;
        }
    }
    printf("%d\n",__count);
    for(int i = 1; i <= ID; i++){
        if(pt[i].size() == 1) continue;
        rua(i);
    }
}
int main(){
    while(scanf("%d %d",&n,&m)!=EOF) solve();
    return 0;
}
posted @ 2020-06-24 21:10  _kiko  阅读(143)  评论(0编辑  收藏  举报