HDU 3488 - 二分图最大权匹配

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3488
题目大意:有n个城市,有m条单向道路把连接起来。你应该重新设计道路。保留一些边。让所有点都在环上。并且每个点只能属于一个环(节点数>=2)。并且要让保留的边权值和最小。可能有重边,保留最小的可以了。
确保至少有一个有效的设计存在。
图片说明
样例:
图片说明
思路:没有自环,那么只要保证每个点只有一个出度和入度就可以了。如果把一个点拆成入点和出点。并且把边权设置为负数。不就是最大权匹配。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=205;
const ll INF=0x3f3f3f3f3f3f3f3f;
struct KuhnMunkres{
    int n;//左右集合点数max(ln, rn)
    ll a[N][N];
    ll hl[N],hr[N],slk[N];//hl hr 左边集合的期望值,右边集合的期望值
    int fl[N],fr[N],vl[N],vr[N],pre[N],q[N],ql,qr;//fl fr,左右匹配对应的点 vl,vr用于bfs标记,
    int check(int i){
        if(vl[i]=1,fl[i]!=-1)return vr[q[qr++]=fl[i]]=1;
        while(i!=-1)swap(i,fr[fl[i]=pre[i]]);
        return 0;
    }
    void bfs(int s){
        memset(slk,0x3f,sizeof(slk));
        memset(vl,0,sizeof(vl));
        memset(vr,0,sizeof(vr));
        q[ql=0]=s;
        vr[s]=qr=1;
        for(ll d;;){
            for(; ql<qr; ++ql)
                for(int i=0,j=q[ql]; i<n; ++i)
                    if(d=hl[i]+hr[j]-a[i][j],!vl[i]&&slk[i]>=d)
                        if(pre[i]=j,d)slk[i]=d;
                        else if(!check(i))return;
            d=INF;
            for(int i=0; i<n; ++i)
                if(!vl[i]&&d>slk[i])d=slk[i];
            for(int i=0; i<n; ++i){
                if(vl[i])hl[i]+=d;
                else slk[i]-=d;
                if(vr[i])hr[i]-=d;
            }
            for(int i=0; i<n; ++i)
                if(!vl[i]&&!slk[i]&&!check(i))return;
        }
    }
    ll ask(int nl, int nr){
        n=max(nl,nr);
        memset(pre,-1,sizeof(pre));
        memset(fl,-1,sizeof(fl));
        memset(fr,-1,sizeof(fr));
        memset(hr,0,sizeof(hr));
        for(int i=0; i<n; ++i) hl[i]=*max_element(a[i],a[i]+n);
        for(int j=0; j<n; ++j) bfs(j);
        long long ans=0;
        for(int i=0; i<n; ++i)
            ans+=a[i][fl[i]];
        return ans;
    }
} km;

/*点编号;[0, n-1]*/
int main(){
    int t, n, m; scanf("%d", &t);
    while(t--){
        ll u, v, w;
        scanf("%d%d", &n, &m);
        for(int i=0; i<n; i++){
            for(int j=0; j<n; j++){
                km.a[i][j]=-INF;
            }
        }
        for(int i=1; i<=m; i++){
            scanf("%lld%lld%lld", &u, &v, &w);
            u--; v--;
            km.a[u][v]=max(km.a[u][v], -w);
        }
        printf("%lld\n", -km.ask(n, n));
    }
    return 0;
}
全部评论

相关推荐

03-13 16:51
已编辑
门头沟学院 硬件开发
点赞 评论 收藏
分享
已oc&nbsp;云智断更了好几天,也有一些话想说,继续更新一篇云智timeline&nbsp;4.18&nbsp;一面&nbsp;半个小时后约二面&nbsp;4.21二面&nbsp;当晚&nbsp;约hr面&nbsp;4.23hr面&nbsp;4.30&nbsp;发offer之前美团的二面挂了,进入人才库,后面又被捞起来面试,4.30号&nbsp;美团又一面,现在还没出一面结果感觉也不报什么希望,就算一面过了,还有二面,我经不起深入拷打,唉,真的,好难五一躺平了五天,吃吃玩玩睡睡~还要担心毕业,科研更是难,唉暑期可能就到此为止了,后面没有时间在这个上面了,要抓紧时间做科研,为了后面能出去实习。大厂,秋招再见!!!有一些感慨:4.1是我的第一次面试,美团,面试的时候紧张到浑身发...
daisy9542:我今晚也是美团一面,已经第六次了。我也面了其他的,没拿到 offer。但我想开了,要按照自己的节奏来,找暑期转正然后秋招大杀四方并不是唯一的出路,其实还有很多选择的,有 0 实习最后秋招拿 offer 了,也有不选择互联网去国企的外企的,考编的,创业的。现在的失败不代表以后的路都是黑暗的,只不过可能运气还没降临到头上。所以现在要做的,就是放平心态,提升自己,通过面试了解到自己的优点和不足,争取下次机会来了能好好抓住
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务