最小路径覆盖(匈牙利算法)

最小路径算法解决以下问题:对于一个DAG,找到最少的路径(连续的若干边)条数(单个顶点也算一条路径),覆盖所有顶点。按路径可否相交分为两类。

首先是路径不相交的最小覆盖

我们可以把每个顶点拆为出点和入点,这时每种路径安排都是一个二分图P',问题转化为了求该二分图的最大匹配:如果在P'中增加一条匹配边pi'-->pj',那么在图P的路径覆盖中就存在一条由pi连接pj的边,也就是说pi与pj 在一条路径上,于是路径覆盖数就可以减少一个。

求解二分图最大匹配用匈牙利算法。

依次遍历每个点尝试寻找增广路。一条增广路满足两端是非匹配点,这样的路径可以通过调整使得匹配数加一。

值得注意的一点是,虽然我们将每个点拆分成了入点和出点,但match数组仍然只保存DAG中的from点,所以在遍历新的点时不需要加上 if(match[i]==0) 的判断,这里是和一般的二分图最大匹配模板有区别的地方。

#include<iostream>
#include<vector>
#include<cstring>

using namespace std;

int n,m;
const int N=500;
int M=5000;

bool dis[N+1][N+1];

bool vis[N+1];
int match[N+1];



int dfs(int u){
    //返回1:能找到增广路
    for(int i=1;i<=n;i++){
        if(dis[u][i]&&!vis[i]){
            vis[i]=true;
            if(match[i]==0||dfs(match[i])){    //如果这个点已经匹配了,就看它匹配的那个点能不能找到新的匹配
                match[i]=u;
                return 1;
            }
        }
    }
    return 0;
}

int hungary(){
    int ans=0;
    memset(match,0,sizeof(match));
    for(int i=1;i<=n;i++){
        memset(vis,0,sizeof(vis));
        ans+=dfs(i);
    }
    return n-ans;    //返回最小路径数
}

如果是路径可相交的情况,通过Floyd求出原图的传递闭包。在这个图上求出的路径不可交的结果即为所求。

证明:为了连通两个点,某条路径可能经过其它路径的中间点。比如1->3->4,2->4->5。但是如果两个点a和b是连通的,只不过中间需要经过其它的点,那么可以在这两个点之间加边,那么a就可以直达b,不必经过中点的,那么就转化成了最小不相交路径覆盖。

void floyd(){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            for(int k=1;k<=n;k++){
                if(dis[i][k]&&dis[k][j]){
                    dis[i][j]=true;
                }
            }
        }
    }
}

模板:poj2594http://poj.org/problem?id=2594

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Absoler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值