Work Scheduling——一般图匹配+带花树算法

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1099

There is a certain amount of night guards that are available to protect the local junkyard from possible junk robberies. These guards need to be scheduled in pairs so that each pair guards in a 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 a number 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.

Example

inputoutput
3
1 2
2 3
1 3
2
1 2

 题目翻译:

有一定数量的夜间警卫,可以保护当地的垃圾场免受可能的垃圾抢劫。这些卫兵需要成对安排,以便每对守卫在不同的夜晚。垃圾场首席执行官命令您编写一个程序,该程序给出防护特征,确定计划守卫的最大数量(其余人员将被解雇)。请注意,每个警卫只能安排与他的一名同事,没有警卫可以单独工作。‎

‎输入‎

‎输入的第一行包含一个数字‎‎N‎‎ = 222,这是一些夜间防护装置。无限数量的线组成无序对 (i ‎‎, ‎‎j‎‎) 跟随, 每个这样的对意味着守卫 # ‎‎i‎‎和守卫 # ‎‎j‎‎可以一起工作, 因为有可能找到适合他们两人的制服 (垃圾场使用不同卫兵的不同部分制服,如头盔、裤子、夹克。不可能把小头盔放在一个长头或大鞋用小脚守卫的护罩上。输入以 Eof 结尾。‎

‎输出‎

‎应输出一个可能的最佳赋值。在输出的第一行上写偶数C,‎‎预定的防护装置的数量。然后输出‎‎C‎‎/2 行,每行包含 2 个整数 (i , ‎‎j‎‎),表示‎‎i‎‎和‎‎j‎‎将协同工作。

经典的一般图匹配带花树算法,这个算法我也只是简单的会用板子,理解好难!,话不多说,上板子。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=300;
int N;
bool G[maxn][maxn];
int match[maxn];
bool InQueue[maxn],InPath[maxn],InBlossom[maxn];
int head,tail;
int Queue[maxn];
int start,finish;
int NewBase;
int father[maxn],Base[maxn];
int Count;
void CreateGraph(){
    int u,v;
    memset(G,0,sizeof(G));
    scanf("%d",&N);
    while(scanf("%d%d",&u,&v)!=EOF){
        G[u][v]=G[v][u]=1;
    }
}
void Push(int u){
    Queue[tail++]=u;
    InQueue[u]=1;
}
int Pop(){
    int res=Queue[head++];
    return res;
}
int FindCommonAncestor(int u,int v){
    memset(InPath,0,sizeof(InPath));
    while(true){
        u=Base[u];
        InPath[u]=1;
        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]]=1;
        u=father[v];
        if(Base[u]!=NewBase)father[u]=v;
    }
}
void BlossomContract(int u,int v){
    NewBase=FindCommonAncestor(u,v);
    memset(InBlossom,0,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])Push(tu);
        }
    }
}
void FindAugmentingPath(){
    memset(InQueue,0,sizeof(InQueue));
    memset(father,0,sizeof(father));
    for(int i=1;i<=N;i++){
        Base[i]=i;
    }
    head=tail=1;
    Push(start);
    finish=0;
    while(head<tail){
        int u=Pop();
        for(int v=1;v<=N;v++){
            if(G[u][v]&&(Base[u]!=Base[v])&&match[u]!=v){
                if((v==start)||(match[v]>0)&&father[match[v]]>0){
                    BlossomContract(u,v);
                } else if(father[v]==0){
                    father[v]=u;
                    if(match[v]>0){
                        Push(match[v]);
                    } 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 u=1;u<=N;u++){
        if(match[u]>0)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(){
    CreateGraph();
    Edmonds();//进行匹配
    PrintMatch();//输出匹配
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值