【hdu1150】【Machine Schedule】二分图最小点覆盖+简单感性证明

这里写图片描述
(上不了p站我要死了,侵权度娘背锅)

题目大意
有两台机器A和B以及N个需要运行的任务。每台机器有M种不同的模式,而每个任务都恰好在一台机器上运行。如果它在机器A上运行,则机器A需要设置为模式ai,如果它在机器B上运行,则机器B需要设置为模式bi。每台机器上的任务可以按照任意顺序执行,但是每台机器每转换一次模式需要重启一次。请合理为每个任务安排一台机器并合理安排顺序,使得机器重启次数尽量少。

因为自己二分图太差啦。。。所以要做点水题补基础。

每个任务有两个属性,则可以考虑用二分图来做。发现我们想用最少的模式来完成所有任务,所以就是一个最小点覆盖问题。

感性证明一下 最小点覆盖=最大匹配:
当我们跑出最大匹配后,匹配点首先是将匹配边覆盖了(这是肯定的),同时也将其他边覆盖了。如果有边没有覆盖,则其两个端点都没有被选择,那么这条边就又是一个匹配了(哇)。所以选择比最大匹配更多的点是没有意义的,而如果选择的点比最大匹配少,则有匹配边没有覆盖。
所以 最小点覆盖=最大匹配

AC代码(end不能用?!竟然CE?!)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

template <typename T>inline void read(T &res){
    T k=1,x=0;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-')k=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    res=x*k;
}

const int N=105;

int n,m,k;
int head[N],to[1005],nxt[1005],hh=0;
int bl[N];
bool vis[N];

void init(){
    memset(bl,0,sizeof(bl));
    memset(head,0,sizeof(head));
    memset(nxt,0,sizeof(nxt));
    memset(to,0,sizeof(to));
    hh=0;
}
void adde(int a,int b){
    hh++;
    to[hh]=b;
    nxt[hh]=head[a];
    head[a]=hh;
}
bool find(int u){
    for(int i=head[u];i;i=nxt[i]){
        int v=to[i];
        if(vis[v]) continue;
        vis[v]=1;
        if(bl[v]==0||find(bl[v])){
            bl[v]=u;
            return true;
        }
    }
    return false;
}
void solve(){
    init();
    read(m),read(k);
    int id,x,y;
    for(int i=1;i<=k;i++){
        read(id),read(x),read(y);
        adde(x,y);
    }
    int cnt=0;
    for(int i=1;i<=n;i++){
        memset(vis,0,sizeof(vis));
        if(find(i)) cnt++;
    }
    printf("%d\n",cnt);
}
int main(){
    while(1){
        read(n);
        if(n==0) break;
        solve();
    }
    return 0;
}
posted @ 2017-10-31 19:08  LinnBlanc  阅读(90)  评论(0编辑  收藏  举报