zoukankan      html  css  js  c++  java
  • BZOJ2278 [Poi2011]Garbage[欧拉回路求环]

    首先研究环上性质,发现如果状态不变的边就不需要动了,每次改的环上边肯定都是起末状态不同的边且仅改一次,因为如果有一条边在多个环上,相当于没有改,无视这条边之后,这几个环显然可以并成一个大环。所以,我们只关注起末状态不同的边。

    然后,这些边形成一张图。对于每个连通块,如果有解的话,应当是一堆边不相交的简单环通过点互相连接的。这样一张图等价于一个欧拉回路,所以只要判每个连通块是不是欧拉回路(偶数度)即可。

    然后是求解,目标就是把每个连通块所有的简单环都拎出来。回顾上述欧拉回路判断,实际上正是因为若干简单环构成的图可以一笔画。。所以仿照一笔画过程(也就是栈中记录的访问点顺序),再开一个栈,不断压栈,当遇到一个先前已经压到栈的点的时候说明形成了一个简单环,一直弹栈直到先前点为止,这时弹出元素就构成了一个环。。这样所有环就出来了。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define mst(x) memset(x,0,sizeof x)
     8 #define dbg(x) cerr << #x << " = " << x <<endl
     9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
    10 using namespace std;
    11 typedef long long ll;
    12 typedef double db;
    13 typedef pair<int,int> pii;
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    19 template<typename T>inline T read(T&x){
    20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    22 }
    23 const int N=1e5+7,M=1e6+7;
    24 struct thxorz{
    25     int head[N],to[M<<1],nxt[M<<1],tot;
    26     thxorz(){tot=1;}
    27     inline void add(int x,int y){
    28         to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
    29         to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
    30     }
    31 }G;
    32 int deg[N],stk[M],vis[M<<1],bin[M],bcnt,top,st[N],tp,instk[N];
    33 int n,m,cnt;
    34 #define y G.to[j]
    35 void dfs(int x){//dbg(x);
    36     for(register int&j=G.head[x];j;j=G.nxt[j])if(!vis[j])vis[j]=vis[j^1]=1,bin[++bcnt]=j,dfs(y);
    37     stk[++top]=x;
    38 }
    39 #undef y
    40 vector<int> ans[M];
    41 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    42     read(n),read(m);
    43     for(register int i=1,x,y,z,w;i<=m;++i){
    44         read(x),read(y),read(z),read(w);
    45         if(z^w)G.add(x,y),++deg[x],++deg[y];
    46     }
    47     for(register int i=1;i<=n;++i)if(deg[i]&1){puts("NIE");return 0;}
    48     for(register int i=1;i<=n;++i)if(G.head[i]){
    49         dfs(i);tp=0;//dbg(i);
    50         while(bcnt)vis[bin[bcnt]]=vis[bin[bcnt]^1]=0,--bcnt;
    51         while(top){
    52             int x=stk[top--];//dbg(x);
    53             if(!instk[x])instk[x]=1,st[++tp]=x;
    54             else{
    55                 ans[++cnt].push_back(x);
    56                 do instk[st[tp]]=0,ans[cnt].push_back(st[tp--]);while(st[tp]^x);
    57                 ans[cnt].push_back(x);
    58             }
    59         }
    60     }
    61     printf("%d
    ",cnt);
    62     for(register int i=1;i<=cnt;++i,puts("")){
    63         printf("%d ",ans[i].size()-1);
    64         for(register int j=0;j<ans[i].size();++j)printf("%d ",ans[i][j]);
    65     }
    66     return 0;
    67 }
    View Code

    总结:这题启示我们在有关简单环的问题中,除了点双、边双等等转化策略以外,在涉及环的方面也可以采用欧拉路来考虑。总之,解决环相关的问题大概就是点双、边双、欧拉路以及栈的思想、dfs以及二分图染色等方法。

  • 相关阅读:
    16位汇编第一讲简介
    COM编程_第一讲_深入COM框架以及实现简单的COM
    COM_第四讲_保存GUID_优化使用代码
    C语言_第二讲_规范以及常用数据类型
    C语言_第一讲_C语言入门
    计算机基础知识_原码反码补码
    计算机基础知识_进制转化
    计算机基础知识_硬件知识
    试题总结2
    试题总结1
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11759341.html
Copyright © 2011-2022 走看看