HDU

题意

给个无向图,无重边和自环,问最少需要多少路径把边覆盖了。并输出相应路径

分析

首先联通块之间是独立的,对于一个联通块内,最少路径覆盖就是  max(1,度数为奇数点的个数/2)。然后就是求欧拉路径了,先将块内度数为奇数的点找出来,留下两个点,其余两两连上虚边,这样我们选择从一个奇数点出发到另一个奇数点,求出一条欧拉路径,统计总路径数。接着就dfs,注意一些细节。

附赠一个求欧拉回路的fleury算法:https://blog.csdn.net/u011466175/article/details/18861415

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define eps 0.0000000001
#define IOS ios::sync_with_stdio(0);cin.tie(0);
#define random(a, b) rand()*rand()%(b-a+1)+a
#define pi acos(-1)
const ll INF = 0x3f3f3f3f3f3f3f3fll;
const int inf = 0x3f3f3f3f;
const int maxn = 100000 + 10;
const int maxm = 200000 + 10;
const int mod = 1e9+7;

struct ND{
    int v,nxt;
    ND(){}
    ND(int _v,int _nxt):v(_v),nxt(_nxt){}
}e[maxn*10];
bool pvis[maxn],evis[maxn*10];
int head[maxn],du[maxn],tot;
int n,m,cnt;
vector<int> ans[maxn],odd;
void init(){
    cnt=tot=0;
    memset(head,-1,sizeof(head));
    memset(du,0,sizeof(du));
    memset(pvis,false,sizeof(pvis));
    memset(evis,false,sizeof(evis));
    for(int i=0;i<=n;i++) ans[i].clear();
}
void addedge(int u,int v){
    e[tot]=ND(v,head[u]);head[u]=tot++;
    e[tot]=ND(u,head[v]);head[v]=tot++;
}
void dfs1(int u){
    pvis[u]=true;
    if(du[u]%2) odd.push_back(u);//同一联通块里奇数度的点
    for(int i=head[u];~i;i=e[i].nxt){
        int v = e[i].v;
        if(!pvis[v]){
            dfs1(v);
        }
    }
}
void dfs2(int u){
    for(int i=head[u];~i;i=e[i].nxt){
        int v=e[i].v;
        if(!evis[i]){
            evis[i]=evis[i^1]=true;//判断边有没有走过
            dfs2(v);
            int tmp=i%2?-(i+1)/2:i/2+1; //对应边的编号
            if(i<2*m) ans[cnt].push_back(tmp); //为原先存在的边
            else cnt++; //新连的虚边
        }
    }
}
int main(){
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
#endif
    while(~scanf("%d%d",&n,&m)){
        init();
        int u,v;
        for(int i=0;i<m;i++){
            scanf("%d%d",&u,&v);
            addedge(u,v);
            du[u]++,du[v]++;
        }
        for(int i=1;i<=n;i++){
            if(!pvis[i]&&du[i]){
                odd.clear();
                dfs1(i);
                for(int i=2;i<odd.size();i+=2){//保留两个奇度点,其余两两连边
                    addedge(odd[i],odd[i+1]);
                }
                int rt = odd.size()?odd[0]:i;
                dfs2(rt);
                cnt++;
            }
        }
        printf("%d
",cnt);
        for(int i=0;i<cnt;i++){
            printf("%d",ans[i].size());
            for(int j=ans[i].size()-1;j>=0;j--){
                printf(" %d",ans[i][j]);
            }puts("");
        }
    }

    return 0;
}
原文地址:https://www.cnblogs.com/fht-litost/p/9551643.html