现在的位置: 首页 > 综合 > 正文

院赛1005(对抗赛)

2013年05月08日 ⁄ 综合 ⁄ 共 2580字 ⁄ 字号 评论关闭

对抗赛

Time Limit:1000MS  Memory Limit:65536K
Total Submit:118 Accepted:6

Description

今年大量新成员的加入给软件协会注入新鲜血液。张女侠,吴大牛和姚大牛主要负责新成员的训练工作。
经过一个暑假的训练,新成员都有了不同程度的成长。为了检测新成员的训练成果,软件协会竞赛部部长决定举行一次新成员对抗赛。比赛分成两队:红队和蓝队。吴大牛和姚大牛各带领一支队伍,张女侠做裁判。
为了公平起见,新成员中互相认识的成员要分在不同队伍,并且两支队伍的人数要相同。每个人有一个编号,编号范围为1—N。

Input

有多组测试数据,每组测试数据第一行为N M,表示共有N人,M对关系。接下来输入M行,每行两个数X和Y,表示X和Y认识(1<=N<=50,1<=M<=100,1<=X,Y<=N且X!=Y)

Output

若可以分配成功进行比赛,输出"Yes!",否则输出"No!"(不包括引号)

Sample Input

20  10
1   11
2   12
3   13
4   14
5   15
6   16
7   17
8   18
9   19
10  20

Sample Output

Yes!

Source

-----------------------------------------------------
最近在看二分匹配,一开始还以为是二分匹配题,囧。。。。
思路完全错误了。。。唉。。
赛后听小雨讲解了下才明白就是:并查集+dfs
思路:用并查集把N个人分成一个个连通集合(就是一棵树),然后用每个连通集再分成两个部分(根据在这棵树中的层数是奇数还是偶数)term[i][0]存第i棵树中层数为偶数的人数,term[i][1]存第i棵树中层数为奇数的人数,然后直接对T个连通集dfs,看是否能使0队和1队的个数都小于等于N/2;

//算法:并查集+dfs
//AC代码:0ms
#include <iostream>
int N,M,T,flag;
int p[105];//储存父节点
int mark[105];//用来标记是否是根节点
int team[105][2];//临时储存
int team1[105][2];//最终每个储存连通图
int find_set(int x)//找父节点
{
 if(p[x]!=x)
  return find_set(p[x]);//只找父节点,不更新
 /*这样会WA*/
 //p[x]=find_set(p[x]);
 //return p[x];
}
int get_degree(int x,int d)//返回层数
{
 if(p[x]==x)
  return d;
 return get_degree(p[x],d+1);
}
void dfs(int k,int s0,int s1)//深搜
{
 if(flag)
  return;
 if(k==T+1)
 {
  if(s0<=N/2&&s1<=N/2)
   flag=1;
  return;
 }
 if(s0>N/2||s1>N/2)
  return;
 dfs(k+1,s0+team1[k][0],s1+team1[k][1]);
 if(flag)//剪枝
  return;
 dfs(k+1,s0+team1[k][1],s1+team1[k][0]);
 return;
}
int main()
{
 int i,x,y,dx,dy,fx,fy;
 while(scanf("%d%d",&N,&M)!=EOF)
 {
  flag=0;
  memset(mark,0,sizeof(mark));
  memset(team,0,sizeof(team));
  for(i=1;i<=N;i++)
   p[i]=i;
  for(i=1;i<=M;i++)
  {
   scanf("%d%d",&x,&y);
   if(flag)
    continue;
   dx=get_degree(x,1);
   dy=get_degree(y,1);
   fx=find_set(x);
   fy=find_set(y);
   if(fx==fy)//在同个树上
   {
    if((dx+dy)%2==0)//如果层数相差为偶数,则直接flag=1,即输"No!"
     flag=1; 
   }
   else
   {
    if((dx+dy)%2==0)//(1)层数奇偶性相同,就根节点相连
    {p[fx]=fy;mark[fy]=1;}
    else//(2)奇偶性不同,就把奇数的根节点连在偶数的当前结点后面
    {
     if(dx&1)
     {p[fx]=y;mark[y]=1;}
     else
     {p[fy]=x;mark[x]=1;}
    }
   }
  }
  if(N&1||flag)//提前判断
  {printf("No!/n");continue;}
  int dans=0;
  for(i=1;i<=N;i++)
  {
   fx=find_set(i);
   dx=get_degree(i,1);
   //printf("%d-",dx);
   if(dx==1&&fx==i&&!mark[i])
    dans++;
   else
   {
    if(dx&1)
     team[fx][1]++;
    else
     team[fx][0]++;
   }
  }
  //printf("%d-",get_degree(7,1));
  if(dans>=N/2)//如果孤立点数>=N/2就直接输出"Yes!"
  {printf("Yes!/n");continue;}
  T=0;
  for(i=1;i<=N;i++)
  {
   if(team[i][0]||team[i][1])
   {
    T++;
    team1[T][0]=team[i][0];
    team1[T][1]=team[i][1];
    //printf("%d-%d/n",team1[T][0],team1[T][1]);
   }
  }
  dfs(1,0,0);
  if(flag)
   printf("Yes!/n");
  else
   printf("No!/n");
 }
 return 0;
}

【上篇】
【下篇】

抱歉!评论已关闭.