poj2942 Knights of the Round Table

125 篇文章 0 订阅

Description Being a knight is a very attractive career: searching for
the Holy Grail, saving damsels in distress, and drinking with the
other knights are fun things to do. Therefore, it is not very
surprising that in recent years the kingdom of King Arthur has
experienced an unprecedented increase in the number of knights. There
are so many knights now, that it is very rare that every Knight of the
Round Table can come at the same time to Camelot and sit around the
round table; usually only a small group of the knights isthere, while
the rest are busy doing heroic deeds around the country.

Knights can easily get over-excited during discussions-especially
after a couple of drinks. After some unfortunate accidents, King
Arthur asked the famous wizard Merlin to make sure that in the future
no fights break out between the knights. After studying the problem
carefully, Merlin realized that the fights can only be prevented if
the knights are seated according to the following two rules:

The knights should be seated such that two knights who hate each other should not be neighbors at the table. (Merlin has a list that

says who hates whom.) The knights are sitting around a roundtable,
thus every knight has exactly two neighbors.
An odd number of knights should sit around the table. This ensures that if the knights cannot agree on something, then they can settle
the issue by voting. (If the number of knights is even, then itcan
happen that yes" andno” have the same number of votes, and the
argument goes on.)

Merlin will let the knights sit down only if these two rules are
satisfied, otherwise he cancels the meeting. (If only one knight shows
up, then the meeting is canceled as well, as one person cannot sit
around a table.) Merlin realized that this means that there can be
knights who cannot be part of any seating arrangements that respect
these rules, and these knights will never be able to sit at the Round
Table (one such case is if a knight hates every other knight, but
there are many other possible reasons). If a knight cannot sit at the
Round Table, then he cannot be a member of the Knights of the Round
Table and must be expelled from the order. These knights have to be
transferred to a less-prestigious order, such as the Knights of the
Square Table, the Knights of the Octagonal Table, or the Knights of
the Banana-Shaped Table. To help Merlin, you have to write a program
that will determine the number of knights that must be expelled.

Input The input contains several blocks of test cases. Each case
begins with a line containing two integers 1 ≤ n ≤ 1000 and 1 ≤ m ≤
1000000 . The number n is the number of knights. The next m lines
describe which knight hates which knight. Each of these m lines
contains two integers k1 and k2 , which means that knight number k1
and knight number k2 hate each other (the numbers k1 and k2 are
between 1 and n ).

The input is terminated by a block with n = m = 0 .

Output For each test case you have to output a single integer on a
separate line: the number of knights that have to be expelled.

在两个可以共存的骑士之间连边,那么问题就变为了寻找不在任何一个简单奇圈里的点的个数。
一个简单圈上的点一定属于一个bcc,那么先求出来bcc。
如果一个bcc不是二分图,那么里面一定含有简单奇圈。这样的话,对于这个bcc里的任何一点u,在奇圈上任取两个点v1,v2,一定可以找到两条互不相交的路线,分别是u->v1和u->v2【因为如果找不到的话,交点就成了这个bcc的割点】。而在奇圈上,v1和v2之间的两条路径一定一奇一偶。这样就可以找到一个包含u的奇圈u->v1->v2->u。换句话说,只要一个bcc不是二分图,那么其中的任何一个点都一定在某一个简单奇圈上。
那么再整理一下思路。建立原图的补图,在新图上求bcc,对每个bcc进行染色判定二分图,标记所有非二分图的bcc里的点,总数减去标记的点的个数就是答案。

#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
using namespace std;
#define M(a) memset(a,0,sizeof(a))
struct edge
{
    int f,t;
}e1,e2;
stack<edge> sta;
vector<edge> to[1010];
vector<int> bcc[1010];
int dfn[1010],low[1010],clo,num[1010],m,n,tot,clr[1010],map[1010][1010];
bool cut[1010],is[1010];
void init()
{
    M(dfn);
    M(low);
    M(num);
    M(cut);
    M(is);
    M(map);
    clo=tot=0;
    while (!sta.empty())
      sta.pop();
    for (int i=1;i<=n;i++)
      to[i].clear();
    for (int i=1;i<=n;i++)
      bcc[i].clear();
}
void in()
{
    int i,j,x,y;
    for (i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        map[x][y]=map[y][x]=1;
    }
    for (i=1;i<=n;i++)
      for (j=i+1;j<=n;j++)
        if (!map[i][j])
        {
            to[i].push_back((edge){i,j});
            to[j].push_back((edge){j,i});
        }
}
void dfs(int u,int fa)
{
    int i,j,k,p,q,v,cnt=0;
    dfn[u]=low[u]=++clo;
    for (i=0;i<to[u].size();i++)
    {
        v=to[u][i].t;
        if (v==fa) continue;
        if (!dfn[v])
        {
            cnt++;
            sta.push(to[u][i]);
            dfs(v,u);
            low[u]=min(low[u],low[v]);
            if (low[v]>=dfn[u])
            {
                tot++;
                cut[u]=1;
                while (1)
                {
                    e1=sta.top();
                    sta.pop();
                    if (num[e1.f]!=tot)
                    {
                        bcc[tot].push_back(e1.f);
                        num[e1.f]=tot;
                    }
                    if (num[e1.t]!=tot)
                    {
                        bcc[tot].push_back(e1.t);
                        num[e1.t]=tot;
                    }
                    if (e1.f==u&&e1.t==v) break;
                }
            }
        }
        else if (dfn[v]<dfn[u])
        {
            sta.push(to[u][i]);
            low[u]=min(low[u],dfn[v]);
        }
    }
    if (cnt==1&&fa==-1) cut[u]=0;
}
void find()
{
    for (int i=1;i<=n;i++)
      if (!dfn[i])
        dfs(i,-1);
}
bool dfs2(int u)
{
    int i,j,k,v;
    for (i=0;i<to[u].size();i++)
    {
        v=to[u][i].t;
        if (num[v]!=num[u]) continue;
        if (clr[v])
        {
            if (clr[v]==clr[u]) return 0;
            continue;
        }
        clr[v]=3-clr[u];
        if (!dfs2(v)) return 0;
    }
    return 1;
}
void mark()
{
    int i,j,k,p,q,x,y,z;
    for (i=1;i<=tot;i++)
    {
        M(clr);
        for (j=0;j<bcc[i].size();j++)
          num[bcc[i][j]]=i;
        clr[bcc[i][0]]=1;
        if (!dfs2(bcc[i][0]))
        {
            for (j=0;j<bcc[i].size();j++)
              is[bcc[i][j]]=1;
        }
    }
}
void out()
{
    int i,ans=n;
    for (i=1;i<=n;i++)
      if (is[i]) ans--;
    printf("%d\n",ans);
}
int main()
{
    while (scanf("%d%d",&n,&m)&&n&&m)
    {
        init();
        in();
        find();
        mark();
        out();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值