Graph(思维题+树结构)

OvO

对于一个结点的儿子,两两配对。所以如果是偶数个就正好。
对于不正好的,让一条边上传,借用到父节点的那条边。一直这么传上去。

if(!fa[v]){
      fa[v]=u;
      q[++t]=v;
}//找一下没有被借用的儿子边。
if(v!=fa[u]&&!vis[i]){
       B[++Neko]=i;
}//把合法的儿子边都加进来
if(v==fa[u]&&!vis[i])B[++Neko]=i;//找一下备用的父亲边
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define int long long
using namespace std;
const int maxn=4e5+1;
int n,m;
int fa[maxn];
int len=0,head[maxn];
int B[maxn],vis[maxn];
int P5=0;
int Fr(int x){return (x&1)?x+1:x-1;}
struct E{int to,next;}e[maxn];
struct E1{int x,y,z;}ans[maxn];
void A(int x,int y){e[++len].to=y;e[len].next=head[x];head[x]=len;}
int q[maxn];
void Dfs(int S){ 
    int h=0,t=1;
    fa[S]=-1;
    q[1]=S;
    while(h<t){
        int u=q[++h];
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(!fa[v]){
                fa[v]=u;
                q[++t]=v;
            }
        }
    } 
    while(t--){
        int u=q[t+1];
        int Neko=0;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(v!=fa[u]&&!vis[i]){
                B[++Neko]=i;
            }
        } 
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(v==fa[u]&&!vis[i])B[++Neko]=i;
        }
        for(int i=1;i+1<=Neko;i+=2){
            vis[B[i]]=1;vis[Fr(B[i])]=1;
            vis[B[i+1]]=1;vis[Fr(B[i+1])]=1;
            ans[++P5].x=e[B[i]].to;
            ans[P5].y=u;
            ans[P5].z=e[B[i+1]].to;
        }
    } 
}
signed main(){
    freopen("graph.in","r",stdin);
    freopen("graph.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=m;i++){
        int v,u;scanf("%lld%lld",&u,&v);
        A(u,v);A(v,u);    
    }  
    for(int i=1;i<=n;i++){
        if(!fa[i])Dfs(i);
    }printf("%lld
",P5);
    for(int i=1;i<=P5;i++){
        printf("%lld %lld %lld
",ans[i].x,ans[i].y,ans[i].z);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/13ZY/p/13805694.html