【LOJ#2162】【POI2011】Garbage(歐拉回路)

【LOJ#2162】【POI2011】Garbage(歐拉回路)

題面

LOJios

題解

首先有一個比較顯然的結論,對於不須要修改顏色的邊能夠直接刪掉,對於須要修改的邊保留。說白點就是每條邊要被訪問的次數能夠直接模二。證實的話就是若是一條邊被通過了兩次,證實其連通了兩側的兩個塊,那麼把這兩次刪掉,能夠把兩側各拆分紅一個歐拉回路,不會影響答案。
因而剩下的邊直接對於每個連通塊算歐拉回路。
而後對於強制定向以後的圖直接\(dfs\)找到全部簡單環就能夠了。spa

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define MAX 100100
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
int n,m;
int f[MAX];
int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
struct Line{int v,next;}e[MAX*20];
int h[MAX],cnt=2,dg[MAX],cur[MAX];
void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;dg[v]++;}
bool vis[MAX*10];int dir[MAX*10];
vector<int> Ans[MAX];int tot;
void dfs(int u)
{
    for(int &i=cur[u];i;i=e[i].next)
    {
        if(vis[i>>1])continue;int j=i;
        vis[i>>1]=true;dfs(e[i].v);
        dir[j>>1]=j&1;
    }
}
int St[MAX],top;bool inq[MAX];
void DFS(int u)
{
    St[++top]=u;inq[u]=true;
    for(int &i=h[u];i;i=e[i].next)
    {
        if(!inq[u])return;
        int v=e[i].v;if((i&1)!=dir[i>>1])continue;
        if(inq[v])
        {
            int p;++tot;Ans[tot].push_back(v);
            do{p=St[top--];Ans[tot].push_back(p);inq[p]=false;}while(p!=v);
            St[++top]=v;inq[v]=true;
        }
        else DFS(v);
    }
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i)f[i]=i;
    for(int i=1;i<=m;++i)
    {
        int u=read(),v=read(),s=read(),t=read();
        if(s^t)Add(u,v),Add(v,u),f[getf(u)]=getf(v);
    }
    for(int i=1;i<=n;++i)if(dg[i]&1){puts("NIE");return 0;}
    for(int i=1;i<=n;++i)cur[i]=h[i];
    for(int i=1;i<=n;++i)if(getf(i)==i)dfs(i);
    for(int i=1;i<=n;++i)DFS(i);
    printf("%d\n",tot);
    for(int i=1;i<=tot;++i)
    {
        printf("%d ",(int)Ans[i].size()-1);
        for(int u:Ans[i])printf("%d ",u);puts("");
    }
    return 0;
}
相關文章
相關標籤/搜索