• 最小路径覆盖问题


    byvoid好神啊Orz
    摘自byvoid的题解

    【问题分析】

    有向无环图最小路径覆盖,可以转化成二分图最大匹配问题,从而用最大流解决。

    【建模方法】

    构造二分图,把原图每个顶点i拆分成二分图X,Y集合中的两个顶点Xi和Yi。对于原图中存在的每条边(i,j),在二分图中连接边(Xi,Yj)。然后把二分图最大匹配模型转化为网络流模型,求网络最大流。

    最小路径覆盖的条数,就是原图顶点数,减去二分图最大匹配数。沿着匹配边查找,就是一个路径上的点,输出所有路径即可。

    【建模分析】

    对于一个路径覆盖,有如下性质:

    1、每个顶点属于且只属于一个路径。
    2、路径上除终点外,从每个顶点出发只有一条边指向路径上的另一顶点。

    所以我们可以把每个顶点理解成两个顶点,一个是出发,一个是目标,建立二分图模型。该二分图的任何一个匹配方案,都对应了一个路径覆盖方案。如果匹配数为0,那么显然路径数=顶点数。每增加一条匹配边,那么路径覆盖数就减少一个,所以路径数=顶点数 - 匹配数。要想使路径数最少,则应最大化匹配数,所以要求二分图的最大匹配。

    注意,此建模方法求最小路径覆盖仅适用于有向无环图,如果有环或是无向图,那么有可能求出的一些环覆盖,而不是路径覆盖。

    #include <queue>
    #include <cstdio>
    #include <cstring>
    const int N=3550,inf=0x3f3f3f3f,S=0,T=302;
    int n,m,head[N],ecnt=1,h[N];
    struct Edge{int to,nxt,val;}e[N*N<<1];
    void add(int bg,int ed,int val){
    	e[++ecnt].nxt=head[bg];
    	e[ecnt].to=ed;
    	head[bg]=ecnt;
    	e[ecnt].val=val;
    }
    std::queue<int>q;
    bool bfs() {
        q.push(S);
        std::memset(h,-1,sizeof h);
        h[S]=0;
        while(!q.empty()) {
            int u=q.front();
            q.pop();
            for(int v,i=head[u]; i; i=e[i].nxt) {
                v=e[i].to;
                if(h[v]==-1&&e[i].val) {
                    h[v]=h[u]+1;
                    q.push(v);
                }
            }
        }
        return h[T]!=-1;
    }
    int dfs(int x,int f) {
        if(x==T)return f;
        int used=0,tp;
        for(int i=head[x]; i; i=e[i].nxt) {
            int v=e[i].to;
            if(h[v]!=h[x]+1||!e[i].val)continue;
            tp=dfs(v,std::min(f-used,e[i].val));
            used+=tp,e[i].val-=tp;
            e[i^1].val+=tp;
            if(used==f)return f;
        }
        if(!used) h[x]=-1;
        return used;
    }
    bool vis[333];
    
    void dfs(int x){
    	for(int i=head[x];i;i=e[i].nxt){
    		if(vis[e[i].to])continue;
    		if(e[i].val==0&&e[i].to>n) {
    			vis[e[i].to-n]=1;
    			printf("%d ",e[i].to-n);
    			dfs(e[i].to-n);return;
    		}
    	}
    }
    int maxflow;
    void dinic() {
        while(bfs())maxflow+=dfs(S,inf);
    }
    void insert(int a,int b,int c){add(a,b,c);add(b,a,0);}
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1,a,b;i<=m;i++) {
    		scanf("%d%d",&a,&b);
    		insert(a,b+n,1);
    	}
    	for(int i=1;i<=n;i++) insert(S,i,1),insert(i+n,T,1);
    	dinic();
    	for(int i=1;i<=n;i++){
    		if(vis[i])continue;
    		printf("%d ",i);vis[i]=1;
    		for(int j=head[i];j;j=e[j].nxt){
    			int v=e[j].to;
    			if(v<=n) continue;
    			if(vis[v-n]) continue;
    			if(!e[j].val) vis[v-n]=1,printf("%d ",v-n),dfs(v-n); 
    		}
    		printf("
    ");
    	}
    	printf("%d",n-maxflow);
    }
    
    我是咸鱼。转载博客请征得博主同意Orz
  • 相关阅读:
    第一章初识java
    初识jQuery
    初识jQuery的案例
    jdk的安装与环境变量的配置
    第六章连接和分组查询
    第五章模糊查询和聚合函数
    第四章数据查询基础
    第三章用sql语句操作数据
    第二章用表组织数据
    第一章数据库系统基础
  • 原文地址:https://www.cnblogs.com/sdfzhsz/p/9266081.html
Copyright © 2020-2023  润新知