[学习笔记] 星空穿越 - 欧拉回路 - 学习笔记

题目大意:给你一张无向图,每条边有一个经过次数的奇偶性,找到尽量少的路径(可以不简单)满足这个条件。
题解:对与要求经过偶数次的边拆成两条边。
然后度数为奇数的点任意配对,跑欧拉回路算法。
欧拉回路算法有个很简单的算法:任意dfs,出栈的时候将入边放到答案序列的前端。
特判一个连通块全是要求经过偶数次的边即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
namespace INPUT_SPACE{
    const int BS=(1<<27)+5;char Buffer[BS],*HD,*TL;
    char gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
    inline int inn()
    {
        int x,ch;while((ch=gc())<'0'||ch>'9');
        x=ch^'0';while((ch=gc())>='0'&&ch<='9')
            x=(x<<1)+(x<<3)+(ch^'0');return x;
    }
}using INPUT_SPACE::inn;
namespace OUTPUT_SPACE{
    char ss[36000000],tt[10];int ssl,ttl;
    inline int PC(char c) { return ss[++ssl]=c; }
    inline int print(int x)
    {
        if(!x) ss[++ssl]='0';
        for(ttl=0;x;x/=10) tt[++ttl]=char(x%10+'0');
        for(;ttl;ttl--) ss[++ssl]=tt[ttl];return 0;
    }
    inline int Flush() { return fwrite(ss+1,sizeof(char),ssl,stdout),0; }
}using OUTPUT_SPACE::print;using OUTPUT_SPACE::PC;using OUTPUT_SPACE::Flush;
const int N=200002,M=500002;
struct edges{
    int to,pre,w;
}e[M<<1];int h[N],etop,vis[N],d[N],del[M<<1],allz,top,s[M];
inline int add_edge(int u,int v,int w) { return e[++etop].to=v,e[etop].pre=h[u],e[etop].w=w,del[etop]=0,h[u]=etop; }
inline int build_edge(int u,int v,int w) { return add_edge(u,v,w),add_edge(v,u,w); }
#define ot(i) ((((i)-1)^1)+1)
#define clr(a,n) memset(a,0,sizeof(int)*((n)+1))
int dfs(int x)
{
    vis[x]=1;
    for(int &i=h[x],j;i;i=e[i].pre)
    {
        if(del[i]) continue;allz&=(e[i].w==0),j=i,
        del[i]=del[ot(i)]=1,dfs(e[i].to),s[++top]=j;
    }
    return 0;
}
vector<int> ans[M];
int main()
{
    for(int T=inn();T;T--)
    {
        int n=inn(),m=inn(),cnt=0;
        clr(h,n),clr(d,n),clr(vis,n),etop=0;
        rep(i,1,m)
        {
            int x=inn(),y=inn(),z=inn();
            build_edge(x,y,z);
            if(!z) build_edge(x,y,z);
            else d[x]^=1,d[y]^=1;
        }
        for(int i=1,las=0;i<=n;i++) if(d[i])
        {   if(las) build_edge(i,las,-1),las=0;else las=i;  }
        rep(i,1,n) if(!vis[i])
        {
            allz=1,top=0,dfs(i);if(allz) continue;int t=cnt+1;
            ans[++cnt].clear(),ans[cnt].pb(e[ot(s[top])].to);
            for(int j=top;j;j--)
            {
                if(e[s[j]].w==-1) ans[++cnt].clear();
                ans[cnt].pb(e[s[j]].to);
            }
            if(t<cnt)
            {
                ans[cnt].pop_back();
                Rep(j,ans[t]) ans[cnt].push_back(ans[t][j]);
                ans[t].clear(),swap(ans[t],ans[cnt]),cnt--;
            }
        }
        print(cnt),PC('\n');
        rep(i,1,cnt)
        {
            print((int)ans[i].size());
            Rep(j,ans[i]) PC(' '),print(ans[i][j]);
            PC('\n');
        }
    }
    return Flush(),0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值