POJ 1325 Machine Schedule 二分图 最小覆盖

传送门


题目大意:
有AB两台机器,A有n个模式0~n-1,B有m个模式0~m-1,现在你需要完成k个任务,每个任务有两个选择,A的i模式或者B的j模式,每台机器可以随意变换模式,但是变换模式需要重启机器,现在希望以最少的重启次数完成任务,请你输出最少输出重启次数


分析:
此题二分图,最小覆盖
这是第三遍写此题了……….
第一遍写的最大匹配……..
第二遍写的最小覆盖……..
第三遍是为了复习最小覆盖……….
复习一下怎么寻找最小覆盖吧!!
满足图中的每一条边都至少有一个点在其中的点集就是图的覆盖,顾名思义,最小覆盖就是点数就最少的覆盖
首先求出图的最大匹配,从每一个左部未匹配节点出发,寻找交错路,标记访问过的节点,取左部未标记节点和右部标记节点,就是最小覆盖
为什么捏??
首先我们可以证明这些点都是匹配点
左部未匹配点一定被标记了(这是显然的),右部未匹配节点一定未被访问(因为最大匹配中不存在增广路,增广路两端节点为未匹配点)……….>_<
如果一条路径属于最大匹配,那么它两端的节点要么都被标记,要么都未被标记,(因为如果i被标记,那么一定会递归进它的匹配点—这是寻找交错路的过程),那么如果一条属于最大匹配的路径,左部节点被标记,右部节点一定也被标记,这时我们选择左部未被标记的和右部被标记的,这样每条路径一定有且只有一个节点属于我们所选取的点集,就是最小覆盖啦~(≧▽≦)/~


代码如下:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
using namespace std;
const int maxn=100+5;
int n,m,k,hd[maxn],to[maxn*maxn],nxt[maxn*maxn],cnt,vis[maxn*2],pre[maxn*2],ans;
int tol[maxn*2],tor[maxn*2],markl[maxn*2],markr[maxn*2];
inline int read(void){
    char ch=getchar();
    int f=1,x=0;
    while(!(ch>='0'&&ch<='9')){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
        x=x*10+ch-'0',ch=getchar();
    return f*x;
}
inline void add(int x,int y){
    if(x==0||y==n)
        return;
    to[cnt]=y;
    nxt[cnt]=hd[x];
    hd[x]=cnt++;
}
inline void find(int u){
    markl[u]=1;
    for(int i=hd[u];i!=-1;i=nxt[i])
        if(tor[to[i]]&&!markr[to[i]]){
            markr[to[i]]=1;
            find(tor[to[i]]);
            break;
        }
}
inline bool dfs(int u){
    for(int i=hd[u];i!=-1;i=nxt[i])
        if(!vis[to[i]]){
            vis[to[i]]=1;
            if(pre[to[i]]==-1||dfs(pre[to[i]])){
                pre[to[i]]=u;
                return true;
            }
        }
    return false;
}
signed main(void){
    while(n=read()){
        cnt=ans=0,memset(hd,-1,sizeof(hd));
        memset(pre,-1,sizeof(pre));
        m=read(),k=read();
        while(k--){
            int s=read(),x=read(),y=read();
            add(x,y+n);
        }
        for(int i=1;i<n;i++){
            memset(vis,0,sizeof(vis));
            dfs(i);
        }
        memset(tor,0,sizeof(tor)),memset(tol,0,sizeof(tol));
        memset(markl,0,sizeof(markl)),memset(markr,0,sizeof(markr));
        for(int i=n+1;i<m+n;i++)
            if(pre[i]!=-1)
                tor[i]=pre[i],tol[pre[i]]=i;
        for(int i=1;i<n;i++)
            if(!tol[i]&&!markl[i])
                find(i);//从每一个未被标记的未匹配的左部节点出发寻找交错路
        for(int i=1;i<n;i++)
            if(!markl[i])//取左部未标记节点--一定是匹配点 
                ans++;
        for(int i=1+n;i<m+n;i++)
            if(markr[i])//取右部标记节点--一定是匹配点 
                ans++; 
        printf("%d\n",ans);
    }
    return 0;
}

by >o< neighthorn

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值