HDU6311 /// 欧拉路径 无向图最小路径覆盖 输出正反路径

题目大意:

给定n m 为图的点数和边数

接下来m行 u v 为u到v有一条边

要求最少几笔能画完图的所有边

输出每笔画过的路径编号 正数编号正向 负数编号反向

题解:https://www.cnblogs.com/xiuwenli/p/9372062.html

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define mem(i,j) memset(i,j,sizeof(i))
using namespace std;
const int N=1e5+5;
int n, m;
struct EDGE {
    int to,nt; int id; bool f;
}E[N<<4];
int head[N], tot;
void addE(int u,int v,int id) {
    E[tot].f=0; E[tot].to=v;
    E[tot].id=id; E[tot].nt=head[u];
    head[u]=tot++;
}
bool vis[N];
int deg[N], cnt;
vector <int> ans[N];
void init() {
    tot=cnt=0; mem(head,-1);
    mem(deg,0); mem(vis,0);
}

void dfs(int u) {
    vis[u]=1;
    for(int i=head[u];~i;i=E[i].nt) {
        int v=E[i].to, id=E[i].id;
        if(!E[i].f) {
            E[i].f=E[i^1].f=1;
            dfs(v);
            if(id) ans[cnt].push_back(-id);
            else cnt++;
        }
    }
}

int main()
{
    while(~scanf("%d%d",&n,&m)) {
        init();
        for(int i=1;i<=m;i++) {
            int u,v; scanf("%d%d",&u,&v);
            deg[u]++, deg[v]++;
            addE(u,v,i); addE(v,u,-i);
        }

        int u=0;
        for(int i=1;i<=n;i++)
            if(deg[i]&1) { // 奇数度的点 两两连边
                if(u) {
                    addE(u,i,0), addE(i,u,0);
                    u=0;
                }
                else u=i;
            }

        for(int i=1;i<=n;i++)
            if(!vis[i] && (deg[i]&1)) {
                cnt++; dfs(i); cnt--;
            }
        for(int i=1;i<=n;i++)
            if(!vis[i] && deg[i]) {
                cnt++; dfs(i);
            }

        printf("%d\n",cnt);
        for(int i=1;i<=cnt;i++) {
            int len=ans[i].size();
            printf("%d",len);
            for(int j=0;j<len;j++)
                printf(" %d",ans[i][j]);
            printf("\n"); ans[i].clear();
        }
    }

    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/zquzjx/p/10312662.html