hdu 5215 Cycle

题意:找到一个图中是否含有奇环和偶环

题解:

1.用了两种发法,一个就是跟bc给的答案一样,先求弱联通分量,再在环中找奇偶环

2.我想到的一个稍微省些代码量的方法,边求联通分量,边判断是否含有奇环偶环,奇环一定能判断出来,但是偶环

能被两个奇数环代替而没有在遍历中发现

3.解决这个问题用到鸽巢定理,先判断有n个联通分量,如果有m个奇环(m > n)则一定有两个奇环在一个连通分量

中,两个奇环可以变成一个偶环,(有个地方需要注意就是:对于单点,当作是一个奇环处理)。

总结:

1.开始想到的解题方法跟标答一样,觉得并不是特别难,写代码的时候感觉特别困,迷迷糊糊的写完了就WA了,睡醒

后,重新一句一句检查代码,感觉状态不好的时候写的代码简直就是恶心,错误百出,以后状态不好的时候直接休

2.后来想到这个优化的方法,写了也WA,第二天才发现题目读错了,这个图可能不是联通的,第一种方法的错误代码

竟然ac了,感觉以后千万不要死扣一个错误,找不到就做会别的事情,再回过头来继续找的时候,也不要局限于一个

范围,着眼于全局查错!

第一种标答方法:

#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define MAXM 300005
int n,m,_,e,top,cnt,bcc,odd,even,ans1,ans2;
int first[MAXN],dfn[MAXN],stack[MAXN];
int id[MAXN],color[MAXN],vis[MAXN];
struct Edge
{
    int next,v;
}edge[MAXM << 1];
void insert(int u,int v)
{
    edge[e].v = v;
    edge[e].next = first[u];
    first[u] = e++;
}
void bipartite(int u,int bcc)
{
    for(int i = first[u];i != -1;i = edge[i].next)if(!vis[i] && !vis[i ^ 1])
    {
        int v = edge[i].v;
        if(id[v] != bcc)continue;
        vis[i] = vis[i ^ 1] = true;
        if(color[v] && color[u] != color[v])even++;
        if(color[u] == color[v])odd++;
        else if(!color[v])
        {
            color[v] = 3 - color[u];
            bipartite(v,bcc);
        }
    }
}
void search(int bcc,int u)
{
    even = odd = 0;
    color[u] = 1;
    bipartite(u,bcc);
    if(odd > 1)even = true;
    ans1 = max(odd,ans1);
    ans2 = max(ans2,even);
}
int dfs(int u,int fa)
{
    int lowu = dfn[u] = ++cnt;
    stack[++top] = u;
    for(int i = first[u];i != -1;i = edge[i].next)if((i ^ 1) != fa)
    {
        int v = edge[i].v;
        if(!dfn[v])
        {
            int lowv = dfs(v,i);
            lowu = min(lowu,lowv);
            if(dfn[u] < lowv)
            {
                bcc++;
                do
                {
                    id[stack[top--]] = bcc;
                }while(stack[top + 1] != v);
            }
        }
        else lowu = min(lowu,dfn[v]);
    }
    return lowu;
}
void solve()
{
    ans1 = ans2 = 0;
    memset(dfn,0,sizeof(dfn));
    memset(color,0,sizeof(color));
    memset(id,0,sizeof(id));
    memset(vis,0,sizeof(vis));
    bcc = cnt = top = 0;
    for(int i = 1;i <= n;i++)if(!dfn[i])dfs(1,-1);
    for(int u = 1;u <= n;u++)
        if(!color[u])
        {
            search(id[u],u);
            if(ans1 && ans2)return;
        }
}
int main()
{
    scanf("%d",&_);
    while(_--)
    {
        scanf("%d%d",&n,&m);
        memset(first,-1,sizeof(first));
        e = 0;
        for(int i = 0;i < m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            insert(u,v),insert(v,u);
        }
        solve();
        if(ans1)puts("YES");
        else puts("NO");
        if(ans2)puts("YES");
        else puts("NO");
    }
}

优化后的方法:

#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define MAXM 300005
int n,m,_,e,top,cnt,bcc,odd,even,point;
int first[MAXN],dfn[MAXN],stack[MAXN],color[MAXN];
bool vis[MAXM << 1];
struct Edge
{
    int next,v;
}edge[MAXM << 1];
void insert(int u,int v)
{
    edge[e].v = v;
    edge[e].next = first[u];
    first[u] = e++;
}
int dfs(int u)
{
    int lowu = dfn[u] = ++cnt;
    stack[++top] = u;
    for(int i = first[u];i != -1;i = edge[i].next)if(!vis[i] && !vis[i ^ 1])
    {
        int v = edge[i].v;
        vis[i] = vis[i ^ 1] = true;
        if(color[v] + color[u] == 3)even++;
        if(color[u] == color[v])odd++;
        if(!dfn[v])
        {
            color[v] = 3 - color[u];
            int lowv = dfs(v);
            lowu = min(lowu,lowv);
            if(dfn[u] < lowv)
            {
                bcc++;
                int num = 0;
                do
                {
                    num++;
                }while(stack[top--] != v);
                if(num == 1)point++;
            }
        }
        else lowu = min(lowu,dfn[v]);
    }
    return lowu;
}
void solve()
{
    even = odd = point = 0;
    memset(dfn,0,sizeof(dfn));
    memset(color,0,sizeof(color));
    memset(vis,false,sizeof(vis));
    bcc = 0;
    cnt = top = 0;
    for(int i = 1;i <= n;i++)if(!dfn[i])
    {
        bcc++;
        color[i] = 1;
        dfs(i);
    }
    if(top == 1)point++;
    if(point + odd > bcc)even++;
}
int main()
{
    scanf("%d",&_);
    while(_--)
    {
        scanf("%d%d",&n,&m);
        memset(first,-1,sizeof(first));
        e = 0;
        for(int i = 0;i < m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            insert(u,v),insert(v,u);
        }
        solve();
        if(odd)puts("YES");
        else puts("NO");
        if(even)puts("YES");
        else puts("NO");
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值