• AGC035 B


    题目传送门

    一句话题意:

     首先,每一条边会产生1个入度,1个出度,因此,如果边的数量是奇数的话,图的所有节点的总出度就是奇数,不可能每个节点的出度都是偶数,因此无解。

    有解时,我们先找出原图中的一棵生成树,然后非树边可以随便定方向。

    接下来从儿子到父亲遍历这棵树。

    对于每个点,我们先处理完所有子节点,然后只考虑这个点与父节点之间边的方向。

    如果当前节点出度为奇数,边的方向就是向父亲,否则,边的方向就是向当前节点。

    这样我们可以保证除根节点外所有节点出度都是偶数。而总边数是偶数,所以根节点出度也是偶数。

    因为奇偶是只需要留一条边来就可以保证的,那么需要确定一个合适的顺序,不会产生矛盾(不知道怎么说,大概就是有时候在图中$dp$需要拓扑排序那种感觉,要确定一个合适的递推顺序)。树就是一种符合这种条件的数据结构。

    上代码:(代码里面有个注释掉的东西,应该是可以那么写的,但是想了想写生成树还是按边来我最顺手,毕竟考试的时候求稳)

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<vector>
      5 using namespace std;
      6 #define N 100005
      7 #define M 100005
      8 struct node{
      9     int u,v;
     10 }edge[M],ans[M];
     11 int n,m,cnt;
     12 vector<int>G[N],T[N];
     13 bool vis[M];
     14 //bool vis[N];
     15 int d[N],ft[N];
     16 int rt=-1;
     17 /*void dfs(int u,int f)
     18 {
     19     vis[u]=1;
     20     for(int i=0;i<G[u].size();i++)
     21     {
     22         int v=G[u][i];
     23         if(vis[v]||v==f) continue;
     24         T[u].push_back(v);
     25         T[v].push_back(u);
     26         dfs(v,u);
     27     }
     28 }*/
     29 int Find(int x)
     30 {
     31     if(ft[x]==x)
     32         return x;
     33     return ft[x]=Find(ft[x]);
     34 }
     35 bool Union(int x,int y)
     36 {
     37     int u=Find(x),v=Find(y);
     38     if(u==v) return 0;
     39     if(u>v) ft[u]=v;
     40     else ft[v]=u;
     41     return 1;    
     42 }
     43 void dfs2(int u,int f)
     44 {
     45     //printf("%d
    ",u);
     46     for(int i=0;i<T[u].size();i++)
     47     {
     48         int v=T[u][i];
     49         if(v==f) continue;
     50         dfs2(v,u);
     51     }
     52     if(u==rt) return ;
     53     if(d[u]&1) ans[++cnt].u=u,ans[cnt].v=f,d[u]++;
     54     else ans[++cnt].u=f,ans[cnt].v=u,d[f]++;
     55     //printf("%d %d %d %d
    ",u,d[u],ans[cnt].u,ans[cnt].v);
     56 }
     57 void Init()
     58 {
     59     for(int i=1;i<=n;i++)
     60         ft[i]=i;
     61     int tot=0;
     62     for(int i=1;i<=m;i++)
     63     {
     64         if(Union(edge[i].u,edge[i].v))
     65         {
     66             T[edge[i].u].push_back(edge[i].v);
     67             T[edge[i].v].push_back(edge[i].u);
     68             if(rt==-1) rt=edge[i].u;
     69             vis[i]=1;
     70             tot++;
     71         }
     72         if(tot==n-1) break;
     73     }
     74     cnt=0;
     75     for(int i=1;i<=m;i++)
     76         if(!vis[i])
     77         {
     78             ans[++cnt].u=edge[i].u,ans[cnt].v=edge[i].v;
     79             d[edge[i].u]++;
     80             //printf("**%d %d
    ",edge[i].u,edge[i].v);
     81         }
     82     dfs2(rt,-1);
     83 }
     84 int main()
     85 {
     86     //freopen("degree.in","r",stdin);
     87     //freopen("degree.out","w",stdout);
     88     scanf("%d %d",&n,&m);
     89     if(m&1)
     90     {
     91         puts("-1");
     92         return 0;
     93     }
     94     for(int i=1;i<=m;i++)
     95     {
     96         int u,v;scanf("%d %d",&u,&v);
     97         G[u].push_back(v);
     98         G[v].push_back(v);
     99         edge[++cnt].u=u,edge[cnt].v=v;
    100     }
    101     //dfs(1);//Find ST
    102     Init();//Find ST
    103     for(int i=1;i<=cnt;i++)
    104         printf("%d %d
    ",ans[i].u,ans[i].v);
    105     return 0;
    106 }
    Code
  • 相关阅读:
    bzoj 4260 Codechef REBXOR——trie树
    bzoj 2238 Mst——树链剖分
    bzoj 2836 魔法树——树链剖分
    CF 888E Maximum Subsequence——折半搜索
    bzoj 4289 PA2012 Tax——构图
    bzoj 4398 福慧双修——二进制分组
    bzoj1116 [POI2008]CLO——并查集找环
    bzoj4241 历史研究——分块
    bzoj4373 算术天才⑨与等差数列——线段树+set
    bzoj4034 [HAOI2015]树上操作——树链剖分
  • 原文地址:https://www.cnblogs.com/lyttt/p/11794737.html
Copyright © 2020-2023  润新知