您的位置:首页 > 其它

poj 2942 双连通+tarjan+割点+奇环判断+二分图染色

2013-08-08 11:13 253 查看
传送门

题意:一群圆桌骑士,坐圆桌开会,相邻俩其实不能互相憎恨,并且骑士数量要为奇数,问一定不可能参加的骑士数量。

吐槽:题意理解很重要啊,一开始理解错了,以为是最少踢多少人可以开会,然后就顺着这思路以为网上代码全是错的。。。。。。。。后来才发现自己理解错了,才恍然大悟。

思路:

整体思路就是找割点,然后将在割点之后存的边拿出来,看是否构成了奇环,如果是,将这些边所连接的点都标记下,最后输出的是没被标记的点的个数。

这题知识点较多,我从看题到学习需要的只是到最后ac也花了很长时间,下面提供点有用的连接。

某妹子博客 这里面讲的很全面,也很详细

二分图染色判断 网上找到的资料,还是蛮好的

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<queue>
using namespace std;
struct edge
{
    int u,v;
};
stack<edge>st;
int n,m,fst[1010],next[1000010],node[1000010];
int edgenum,dfn[1010],low[1010],num;
int color[1010],ans;
bool l[1010][1010],ok[1010],p[1010][1010],mark[1010];
void init()
{
    num=0;
    ans=0;
    edgenum=0;
    memset(l,0,sizeof(l));
    memset(p,0,sizeof(p));
    memset(ok,0,sizeof(ok));
    memset(dfn,0,sizeof(dfn));
    memset(fst,-1,sizeof(fst));
    int u,v;
    for(int i=0; i<m; i++)
    {
        scanf("%d%d",&u,&v);
        l[u][v]=1;
        l[v][u]=1;
    }
}
void graph()
{
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if(i!=j&&!l[i][j])
            {
                next[++edgenum]=fst[i];
                fst[i]=edgenum;
                node[edgenum]=j;
            }
        }
    }
}
bool odd(int x)
{
    int u,v;
    queue<int>q;
    q.push(x);
    color[x]=1;
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        for(int i=fst[u]; i!=-1; i=next[i])
        {
            v=node[i];
            if(mark[v])
            {
                if(color[v]==0)
                {
                    color[v]=-color[u];
                    q.push(v);
                }
                else if(color[u]==color[v])return true;
            }
        }
    }
    return false;
}
void paint(int u,edge temp)
{
    edge ed;
    memset(mark,0,sizeof(mark));
    memset(color,0,sizeof(color));
    do
    {
        ed=st.top();
        st.pop();
        mark[ed.u]=mark[ed.v]=1;
    }
    while((ed.u!=temp.u)||(ed.v!=temp.v));
    if(odd(u))
    {
        for(int i=1; i<=n; i++)
        {
            if(mark[i])ok[i]=1;
        }
    }
}
void tarjan(int u)
{
    int v;
    dfn[u]=low[u]=++num;
    for(int i=fst[u]; i!=-1; i=next[i])
    {
        v=node[i];
        if(!p[u][v])
        {
            edge temp;
            temp.u=u;
            temp.v=v;
            st.push(temp);
            p[u][v]=p[v][u]=1;
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
                if(low[v]>=dfn[u])paint(u,temp);
            }
            else low[u]=min(low[u],dfn[v]);
        }
    }
}
void solve()
{
    for(int i=1; i<=n; i++)
    {
        if(!dfn[i])tarjan(i);
    }
    for(int i=1; i<=n; i++)
    {
        if(!ok[i])ans++;
    }
    printf("%d\n",ans);
}
int main()
{
    while(scanf("%d%d",&n,&m)&&n)
    {
        init();
        graph();
        solve();
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: