zoukankan      html  css  js  c++  java
  • 神奇脑洞题解——HDU1853 Cyclic Tour

    对于二分图的最大匹配和对于带权二分图的最优匹配,B站上

    CSU ACM—ICPC 的大佬们讲的已经很清楚了。

    有需求的同学们可以去B站上学习一下。

    悄悄说一声,讲课的陈佳妮小姐姐也曾经是位OIer,曾在CTSC2016上夺得银牌(因为在HN,好像没能去成NOI),讲解的方式也令OIers十分舒适。

    题目大意:给一张有向图,要求选择任意多个环(可重复,非自环,环可以任选,不用相连),使得每个点都被访问过,而且经过的边权之和最小,求最小值

    乍一看和二分图没有关系,但是仔细想一下,如果给图中每个点拆成两个(一个连接这个点的入点,一个连出点),那么因为要走环,那么最优情况肯定是每个环中有一个点会被访问两次,其他点都是一次,那这不就是赤果果的在拆点图上求最优匹配吗?

    假设我们有一张图:1——>2——>3——>1,设拆出来的点i,用来连接入点的是i,连接出点的是i+n(此处n=4),那么我们拆点图长这样:5——>2,6——>3,

    7——>1,这样就实际上是对拆出来的六个点进行了一次完全匹配。

    那么,我们只要先判断拆点图能不能形成完美匹配,然后再跑一边KM就可以了(KM算法要求二分图存在完美匹配,否则会陷入死循环)。

    放代码吧:

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    vector<int>b[101];
    int n,m;
    struct PE
    {
        int s,t,val;
    };
    PE E[20001];
    int mp[101][101];
    bool Function(PE x,PE y)
    {
        return x.val<y.val;
    }
    int QWx[101],QWy[101],use[101],pre[101],stx[101];
    int visx[101],visy[101],fpre[101];
    bool Hungary(int x)
    {
        int temp=0;
        visx[x]=1;
        for(int i=0;i<b[x].size();i++)
        {
            int to=b[x][i];
            if(visy[to])
            {
                continue;
            }
            temp=QWx[x]+QWy[to]-mp[x][to];
            if(temp==0)
            {
                visy[to]=1;
                if(pre[to]==0||Hungary(pre[to]))
                {
                    fpre[x]=to;
                    pre[to]=x;
                    return 1;
                }
            }
            else
                stx[to]=min(stx[to],temp);
        }
        return 0;
    }
    bool PDHungary(int x)
    {
        for(int i=0;i<b[x].size();i++)
        {
            int to=b[x][i];
            if(visy[to])
                continue;
            visy[to]=1;
            if(pre[to]==0||PDHungary(pre[to]))
            {
                pre[to]=x;
                return 1;
            }
        }
        return 0;
    }
    void KM()
    {
        for(int i=1;i<=n;i++)
        {
            memset(stx,0x3f3f3f3f,sizeof(stx));
            
            while(1)
            {
                memset(visx,0,sizeof(visx));
                memset(visy,0,sizeof(visy));
                if(Hungary(i))
                {
                    break;
                }
                else
                {
                    int date=0x3f3f3f3f;
                    for(int j=1;j<=n;j++)
                    {
                        if(!visy[j])
                        date=min(date,stx[j]);
                    }
                    for(int j=1;j<=n;j++)
                    {
                        if(visx[j])
                            QWx[j]-=date;
                        if(visy[j])
                            QWy[j]+=date;
                        else
                            stx[j]-=date;
                    }
                }
            }
        }
    }
    int LINYIN()
    {
        //scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            b[i].clear();
        }
        int ans=0;
        memset(mp,-0x3f3f3f3f,sizeof(mp));
        memset(QWx,-0x3f3f3f3f,sizeof(QWx));
        memset(QWy,0,sizeof(QWy));
        memset(pre,0,sizeof(pre));
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&E[i].s,&E[i].t,&E[i].val);
            E[i].val*=-1;
        }
        sort(E+1,E+1+m,Function);
        mp[E[1].s][E[1].t]=E[1].val;
        b[E[1].s].push_back(E[1].t);
        for(int i=2;i<=m;i++)
        {
            if(E[i].s==E[i-1].s&&E[i].t==E[i-1].t&&E[i].val==E[i-1].val)
                continue;
            mp[E[i].s][E[i].t]=max(mp[E[i].s][E[i].t],E[i].val);
            b[E[i].s].push_back(E[i].t);
            QWx[E[i].s]=max(QWx[E[i].s],E[i].val);    
        }
        for(int i=1;i<=n;i++)
        {
            memset(visy,0,sizeof(visy));
            if(!PDHungary(i))
            {
                printf("%d
    ",-1);
                return 0;
            }
        }
        memset(pre,0,sizeof(pre));
        memset(visy,0,sizeof(visy));
        KM();
        for(int i=1;i<=n;i++)
        {
            ans+=mp[pre[i]][i];
        } 
        ans*=-1;
        printf("%d
    ",ans);
        return 0;
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            LINYIN();
        }
        return 0;
    }

    完结撒花!

  • 相关阅读:
    Java中equals与==异同
    CGI与WSGI
    Javazh中static的简单理解
    MySQL 4.1/5.0/5.1/5.5各版本的主要区别
    php生成随机密码的几种方法
    phpmyadmin里MySQL字符集:cp1252 West European (latin1) ,解决乱码问题
    GoogleMap API 离线版
    [转]为前端开发人员制作的 Chrome 扩展 jsbeautifier
    Google Map Tile 下载脚本
    Google 地图 API 参考
  • 原文地址:https://www.cnblogs.com/XLINYIN/p/11784852.html
Copyright © 2011-2022 走看看