URAL 1099. Work Scheduling 一般图匹配带花树

一般图匹配带花树模版题:

将奇环缩成圈(Blossom),然后找增广路.....

1099. Work Scheduling

Time limit: 0.5 second

Memory limit: 64 MB

There is certain amount of night guards that are available to protect the local junkyard from possible junk robberies. These guards need to scheduled in pairs, so that each pair guards at different
night. The junkyard CEO ordered you to write a program which given the guards characteristics determines the maximum amount of scheduled guards (the rest will be fired). Please note that each guard can be scheduled with only one of his colleagues and no guard
can work alone.

Input

The first line of the input contains one number N ≤ 222 which is the amount of night guards. Unlimited number of lines consisting of unordered pairs (ij) follow, each such
pair means that guard #i and guard #j can work together, because it is possible to find uniforms that suit both of them (The junkyard uses different parts of uniforms for different guards i.e. helmets, pants, jackets. It is impossible to
put small helmet on a guard with a big head or big shoes on guard with small feet). The input ends with Eof.

Output

You should output one possible optimal assignment. On the first line of the output write the even number C, the amount of scheduled guards. Then output C/2 lines, each containing 2
integers (ij) that denote that i and j will work together.

Sample

input output
3
1 2
2 3
1 3
2
1 2

Problem Author: Jivko Ganev

Tags: graph theory  (

hide tags for unsolved problems
)

Difficulty: 1356    Printable version    Submit solution    Discussion
(51)

My submissions    All submissions (15804)    All
accepted submissions (1687)
   Solutions rating (610)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int maxn=250;

/*******************************************/

struct Edge
{
  int to,next;
}edge[maxn*maxn];

int Adj[maxn],Size;

void init()
{
  memset(Adj,-1,sizeof(Adj)); Size=0;
}

void add_edge(int u,int v)
{
  edge[Size].to=v; edge[Size].next=Adj[u]; Adj[u]=Size++;
}

/*******************************************/

int n;
int Match[maxn];
bool G[maxn][maxn];
int Start,Finish,NewBase;
int Father[maxn],Base[maxn];
bool InQueue[maxn],InPath[maxn],InBlossom[maxn];
int Count;
queue<int> q;

int FindCommonAncestor(int u,int v)
{
  memset(InPath,false,sizeof(InPath));
  while(true)
    {
      u=Base[u];
      InPath[u]=true;
      if(u==Start) break;
      u=Father[Match[u]];
    }
  while(true)
    {
      v=Base[v];
      if(InPath[v]) break;
      v=Father[Match[v]];
    }
  return v;
}

void ResetTrace(int u)
{
  int v;
  while(Base[u]!=NewBase)
    {
      v=Match[u];
      InBlossom[Base[u]]=InBlossom[Base[v]]=true;
      u=Father[v];
      if(Base[u]!=NewBase) Father[u]=v;
    }
}

void BlosomContract(int u,int v)
{
  NewBase=FindCommonAncestor(u,v);
  memset(InBlossom,false,sizeof(InBlossom));
  ResetTrace(u);
  ResetTrace(v);
  if(Base[u]!=NewBase) Father[u]=v;
  if(Base[v]!=NewBase) Father[v]=u;
  for(int tu=1;tu<=n;tu++)
    {
      if(InBlossom[Base[tu]])
        {
          Base[tu]=NewBase;
          if(!InQueue[tu])
            {
              q.push(tu);
              InQueue[tu]=true;
            }
        }
    }
}

void FindAugmentingPath()
{
  memset(InQueue,false,sizeof(InQueue));
  memset(Father,0,sizeof(Father));
  for(int i=1;i<=n;i++)
    Base[i]=i;
  while(!q.empty()) q.pop();
  q.push(Start); InQueue[Start]=true;
  Finish=0;

  while(!q.empty())
    {
      int u=q.front(); //InQueue[u]=false;
      q.pop();
      for(int i=Adj[u];~i;i=edge[i].next)
        {
          int v=edge[i].to;
          if((Base[u]!=Base[v])&&Match[u]!=v)
            {
              if(v==Start||(Match[v]>0&&Father[Match[v]]>0))
                BlosomContract(u,v);
              else if(Father[v]==0)
                {
                  Father[v]=u;
                  if(Match[v]>0)
                    {
                      q.push(Match[v]);
                      InQueue[Match[v]]=true;
                    }
                  else
                    {
                      Finish=v;
                      return ;
                    }
                }
            }
        }
    }
}

void AugmentPath()
{
  int u,v,w;
  u=Finish;
  while(u>0)
    {
      v=Father[u];
      w=Match[v];
      Match[v]=u;
      Match[u]=v;
      u=w;
    }
}

void Edmonds()
{
  memset(Match,0,sizeof(Match));
  for(int u=1;u<=n;u++)
    {
      if(Match[u]==0)
        {
          Start=u;
          FindAugmentingPath();
          if(Finish>0) AugmentPath();
        }
    }
}

void PrintMatch()
{
  Count=0;
  for(int i=1;i<=n;i++)
    {
      if(Match[i]) Count++;
    }
  printf("%d\n",Count);
  for(int u=1;u<=n;u++)
    {
      if(u<Match[u])
        printf("%d %d\n",u,Match[u]);
    }
}

int main()
{
  //freopen("data.in","r",stdin);
  while(scanf("%d",&n)!=EOF)
    {
      init();
      memset(G,false,sizeof(G));
      int u,v;
      while(scanf("%d%d",&u,&v)!=EOF)
        {
          if(G[u][v]==true) continue;
          G[u][v]=G[v][u]=true;
          add_edge(u,v);
          add_edge(v,u);
        }
      Edmonds();
      PrintMatch();
    }
  return 0;
}
时间: 2024-10-11 08:20:17

URAL 1099. Work Scheduling 一般图匹配带花树的相关文章

kuangbin带你飞 匹配问题 二分匹配 + 二分图多重匹配 + 二分图最大权匹配 + 一般图匹配带花树

二分匹配:二分图的一些性质 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图. 1.一个二分图中的最大匹配数等于这个图中的最小点覆盖数 König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数.如果你还不知道什么是最小点覆盖,我也在这里说一下:假如选

URAL 1099 Work scheduling 一般图的最大匹配 带花树算法(模板)

R - Work scheduling Time Limit:500MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice URAL 1099 Description There is certain amount of night guards that are available to protect the local junkyard from possible junk r

一般图匹配带花树

R - Work Scheduling Time Limit:500MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice URAL 1099 Appoint description: Description There is certain amount of night guards that are available to protect the local junkyard

HDU 4687 Boke and Tsukkomi(一般图匹配|带花树)

比赛的时候刚开始看这题还以为是二分图匹配,后来才发现根本不是,因为该题存在长度为奇数的圈 .  比如1->2,2->3,3->1 . 所以该题要用一般图匹配,即带花树算法 . 比赛时抄的模板有地方抄错了,上述样例出现了死循环 .   赛后补题的时候用map去重却得不到正确答案,不知为何,暂放 ,下面给出一种正确解法. 细节参见代码: #include<cstdio> #include<cstring> #include<iostream> #inclu

HDU 4687 Boke and Tsukkomi 一般图匹配,带花树,思路,输出注意空行 难度:4

http://acm.hdu.edu.cn/showproblem.php?pid=4687 此题求哪些边在任何一般图极大匹配中都无用,对于任意一条边i,设i的两个端点分别为si,ti, 则任意一个极大匹配中都必然有si或ti至少一个点被匹配,当在图中去掉si,ti两个点时,匹配数会损失一个或两个. 如果损失两个,就说明在极大匹配中这两个点分别连接不同的边,于是边i是无用的 所以总体思路:一般图匹配求出最大匹配数cnt0,分别试着去掉每条边的端点,再次匹配,匹配数如果小于cnt0-1,则这条边无

HDOJ 4687 Boke and Tsukkomi 一般图最大匹配带花树+暴力

一般图最大匹配带花树+暴力: 先算最大匹配 C1 在枚举每一条边,去掉和这条边两个端点有关的边.....再跑Edmonds得到匹配C2 如果C2+2==C1则这条边再某个最大匹配中 Boke and Tsukkomi Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total Submission(s): 649    Accepted Submission(s): 202

poj 3020 一般图最大匹配 带花树开花算法

题意: 给出一个h*w的图,每个点都是'o'或'*',最少要用多少个1*2的矩形才能把图中所有的'*'都覆盖掉. 限制: 1 <= h <= 40; 1 <= w <= 10 思路: 最小边覆盖=|V|-最大匹配 一般图最大匹配,带花树开花算法 /*poj 3020 一般图最大匹配 带花树开花算法 题意: 给出一个h*w的图,每个点都是'o'或'*',最少要用多少个1*2的矩形才能把图中所有的'*'都覆盖掉. 限制: 1 <= h <= 40; 1 <= w &l

ZOJ 3316 Game 一般图最大匹配带花树

一般图最大匹配带花树: 建图后,计算最大匹配数. 如果有一个联通块不是完美匹配,先手就可以走那个没被匹配到的点,后手不论怎么走,都必然走到一个被匹配的点上,先手就可以顺着这个交错路走下去,最后一定是后手没有路可走,因为如果还有路可走,这一条交错路,就是一个增广路,必然有更大的匹配. Game Time Limit: 1 Second      Memory Limit: 32768 KB Fire and Lam are addicted to the game of Go recently.

URAL 1099 Work Scheduling

一般图的最大匹配  带花树开花算法 有两个模板,一个kuangbin大神的,另一个不知道谁写的. #include<stdio.h> #include<string.h> #include<string.h> #include<iostream> #include<queue> #include<algorithm> using namespace std; const int MAXN = 250; int N; //点的个数,点的