【Codeforces Beta Round #19】Codeforces 19E Fairy

177 篇文章 0 订阅
87 篇文章 1 订阅

Once upon a time there lived a good fairy A. One day a fine young man
B came to her and asked to predict his future. The fairy looked into
her magic ball and said that soon the fine young man will meet the
most beautiful princess ever and will marry her. Then she drew on a
sheet of paper n points and joined some of them with segments, each of
the segments starts in some point and ends in some other point. Having
drawn that picture, she asked the young man to erase one of the
segments from the sheet. Then she tries to colour each point red or
blue so, that there is no segment having points of the same colour as
its ends. If she manages to do so, the prediction will come true. B
wants to meet the most beautiful princess, that’s why he asks you to
help him. Find all the segments that will help him to meet the
princess.

Input The first input line contains two integer numbers: n — amount of
the drawn points and m — amount of the drawn segments
(1 ≤ n ≤ 104, 0 ≤ m ≤ 104). The following m lines contain the
descriptions of the segments. Each description contains two different
space-separated integer numbers v, u (1 ≤ v ≤ n, 1 ≤ u ≤ n) — indexes
of the points, joined by this segment. No segment is met in the
description twice.

Output In the first line output number k — amount of the segments in
the answer. In the second line output k space-separated numbers —
indexes of these segments in ascending order. Each index should be
output only once. Segments are numbered from 1 in the input order.

一个没有简单奇环的图,一定没有奇环。所以题目要找的就是覆盖所有简单奇环的边。在dfs树上,简单环与返祖边一一对应。所以在dfs的时候每遇到一个返祖边,就差分标记路径。最后找到被所有路径覆盖的树边。
上面这个只是解法的思路,实现起来有很多细节:

  • 如果某个树边在一个偶环上,删除它之后会产生新的奇环,所以还要差分标记一下偶环个数。
  • 构成奇环的返祖边可以被纳入答案,当且仅当图中只有一个奇环【因为他只能覆盖一个奇环】。
  • 如果图中没有奇环,可以随意删除一条边。
  • 注意原图不联通的情况。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
int fa[10010],c1[10010],c0[10010],dep[10010],s0[10010],s1[10010],
from[10010],b0[10010],b1[10010],n,m,m1,m0;
vector<pair<int,int> > to[10010];
vector<int> ans;
void init()
{
    int i,u,v;
    scanf("%d%d",&n,&m);
    for (i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        to[u].push_back(make_pair(v,i));
        to[v].push_back(make_pair(u,i));
    }
}
void dfs1(int u)
{
    int i,v;
    for (i=0;i<to[u].size();i++)
      if ((v=to[u][i].first)!=fa[u])
      {
        if (!dep[v])
        {
            dep[v]=dep[u]+1;
            fa[v]=u;
            from[v]=to[u][i].second;
            dfs1(v);
            s0[u]+=s0[v];
            s1[u]+=s1[v];
        }
        else if (dep[v]<dep[u])
        {
            if (dep[v]-dep[u]&1)
            {
                m0++;
                c0[u]++;
                c0[v]--;
                b0[to[u][i].second]=1;
            }
            else
            {
                m1++;
                c1[u]++;
                c1[v]--;
                b1[to[u][i].second]=1;
            }
        }
      }
    s0[u]+=c0[u];
    s1[u]+=c1[u];
}
int solve()
{
    int i,ret=0;
    if (!m1)
    {
        for (i=1;i<=m;i++)
          ans.push_back(i);
        return m;
    }
    for (i=1;i<=n;i++)
      if (s1[i]==m1&&!s0[i])
      {
        ret++;
        ans.push_back(from[i]);
      }
    if (m1==1)
    {
        ret++;
        for (i=1;i<=m;i++)
          if (b1[i])
          {
            ans.push_back(i);
            break;
          }
    }
    return ret;
}
int main()
{
    int i;
    init();
    for (i=1;i<=n;i++)
      if (!dep[i])
      {
        dep[i]=1;
        dfs1(i);
      }
    printf("%d\n",solve());
    sort(ans.begin(),ans.end());
    for (i=0;i<ans.size();i++)
      printf("%d%c",ans[i],i==ans.size()-1?'\n':' ');
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值