• 二分图变种之最小路径覆盖、最小点覆盖集【poj3041】【poj2060】


    这里写图片描述
    [pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=54859604
    向大(hei)佬(e)势力学(di)习(tou)

    二分图其实早就学了,可是无赖自己当初没好好听讲,变种就不说了,连匈牙利算法都不会。这次给了我一个好好复习改过自新的机会,既把匈牙利搞熟了,也算是理解了一些变种。

    最小路径覆盖:

    题意
    用最少的出租车送完所有的乘客

    将时间上可以接上的乘客连边
    在一个图中,希望用最少的路径将所有点走遍,为什么 最小路径数=点总数-最大匹配 呢?
    一张图,如果我们先暴力的各用一条路径把点覆盖
    (拆点,连边表示可到达,虚线是假设的)
    这里写图片描述
    那么每多一个匹配,就可以少一个路径(车)。
    代码

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    
    const int oo=0x3f3f3f3f;
    
    int m,h[505],mm[505],tim[505],st[505][2],en[505][2];
    int top,hh,head[1010];
    struct Node{
        int to,nxt;
    }a[250010];
    int vis[1010],girl[1010];
    
    void adde(int fr,int to,int val){
        hh++;
        a[hh].to=to;
        a[hh].nxt=head[fr];
    }
    int dis(int x){
        return abs(st[x][0]-en[x][0])+abs(st[x][1]-en[x][1]);
    }
    int diss(int a,int b){
        return abs(en[a][0]-st[b][0])+abs(en[a][1]-st[b][1]);
    }
    bool find(int x){//printf("/");
        for(int i=head[x];i;i=a[i].nxt){//printf("he ");
            int v=a[i].to;
            if(!vis[v]){
                vis[v]=1;
                if(girl[v]==0||find(girl[v])){
                    girl[v]=x;
                    return true;
                }
            }
        }
        return false;
    }
    int hungary(){
        int rt=0;
        for(int i=1;i<=m;i++){
            memset(vis,0,sizeof(vis));
            if(find(i)) rt++;
        }
        return rt;
    }
    void solve(){
        memset(a,0,sizeof(a));
        memset(head,0,sizeof(head));
        memset(girl,0,sizeof(girl));
        scanf("%d",&m);
        top=2*m+1;hh=1;
        char str[10];
        for(int i=1;i<=m;i++){
            scanf("%s",str);
            h[i]=(str[0]-'0')*10+(str[1]-'0');
            mm[i]=(str[3]-'0')*10+(str[4]-'0');
            tim[i]=h[i]*60+mm[i];//printf("tim[%d]=%d
    ",i,tim[i]);
            scanf("%d%d%d%d",&st[i][0],&st[i][1],&en[i][0],&en[i][1]);
        }
        for(int i=1;i<m;i++){
            for(int j=i+1;j<=m;j++){
                if(tim[i]+dis(i)+diss(i,j)<tim[j]){
                    adde(i,m+j,1);//printf("he ");
                }
            }
        }
        int ans=0;
        ans=hungary();
        printf("%d
    ",m-ans);
    }
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            solve();
        }
        return 0;
    }

    最小点覆盖集:
    最小点覆盖=最大匹配
    为什么呢?假设还有一条边没有被覆盖,即它连的两个点都还没有被纳入匹配,那么这又是一个匹配了

    题意
    在n*n的方格中,放着一些东西。我有一个武器,每次可以清除一横排或一纵列,问最小使用次数

    裸体一道,A的人太多了。然而对初学者来说,是开拓新思维。将行与列拆成两个点,两边即为一个点
    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N=10000+5;
    
    int n,k,r[N],c[N];
    int head[3*N],end[6*N],nxt[6*N],hh=0;
    int vis[3*N],girl[3*N];
    
    void adde(int a,int b){
        hh++;
        end[hh]=b;
        nxt[hh]=head[a];
        head[a]=hh;
    }
    bool find(int u){
        for(int i=head[u];i;i=nxt[i]){
            int v=end[i];
            if(!vis[v]){
                vis[v]=1;
                if(girl[v]==0||find(girl[v])){
                    girl[v]=u;
                    return true;
                }
            }
        }
        return false;
    }
    int hungary(){
        int rt=0;
        for(int i=1;i<=n;i++){
            memset(vis,0,sizeof(vis));
            if(find(i)) rt++;
        }
        return rt;
    }
    int main(){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=k;i++){
            scanf("%d%d",&r[i],&c[i]);
            adde(r[i],c[i]+n);//建边注意 
        }
        printf("%d",hungary());
        return 0;
    }

    总结:
    1、此次算是学懂了一些了,二分图的变通就在于构图上,其中拆点的思想尤为重要,还需多练

  • 相关阅读:
    Freesql使用一张带父子关系的表,生成list树型数据
    css特效实现html表格显示部分内容,当鼠标移上去显示全部。
    ASP.NET Core如何自动生成小写的破折号路由
    windows服务+OpenSSH+SVN在Jenkins上的自动化部署进阶篇
    Windows+.Net Framework+svn+IIS在Jenkins上的自动化部署入门
    .net(C#)中结构和类的区别
    Web.config配置详解
    关于Asp.net core配置信息读取的源码分析梳理
    极简实用的Asp.NetCore框架再新增商城模块
    极简实用的Asp.NetCore模块化框架新增CMS模块
  • 原文地址:https://www.cnblogs.com/LinnBlanc/p/7763156.html
Copyright © 2020-2023  润新知