【网络流】最小路径覆盖

最小边覆盖=最大独立集=n-最大匹配
这个是在原图是二分图上进行的
最小路径覆盖
最小边覆盖不同不要求给的图是二分图,而是要求是PXP的有向图,不能有环,然后根据原图构造二分图,构造方法是将点一分为二,如,i分为i1和i2然后如果i和j有边,那么就在i1和j2之间连一条边。由此构成二分图

然后最小路径覆盖是n-m,n为原图的点的个数,m为新造二分图的最大匹配。证明也是特别简单的,根据定义最小路径覆盖里要求同一个点只可以属于一条路径,即路径时不可以开叉的,如果在二分图里选两条有公共点的边那么反应在原图上就是路径有岔路了,所以二分图里选的边必须是无公共交点的,这就是转化到最大匹配了。


/*Author : Soap
  Problem : 网络流24题 03  
  Date : 2014-04-04 15:10
  Statu : AC 
  Solution : 最小路径覆盖模板题  ;二分图匹配建边CAP均为1;DFS输出路径 
*/ 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxm 40000
#define maxn 10001
#define INF 0x3f3f3f3f

struct E{
       int to,cap,op,next;
       }e[maxm];

int tot,head[maxn],S,T,nodes,gap[maxm],dep[maxn],n,m,maxflow;
bool v[maxn];
        
void add(int x,int y,int w){
     e[++tot].to=y; e[tot].cap=w; e[tot].op=tot+1; e[tot].next=head[x]; head[x]=tot;
     e[++tot].to=x; e[tot].cap=0; e[tot].op=tot-1; e[tot].next=head[y]; head[y]=tot;
}

int  SAP(int t,int delta){
   if (t==T) return delta;
   int mindis=nodes,sum=0;
   for (int i=head[t];i;i=e[i].next){
        if (e[i].cap>0 && dep[e[i].to]+1==dep[t]){
           int save=SAP(e[i].to,min(delta-sum,e[i].cap));
           e[i].cap-=save;
           e[e[i].op].cap+=save;
           sum+=save;
           if (sum==delta || dep[S]>=nodes) return sum;
           }
        if (e[i].cap>0) mindis=min(mindis,dep[e[i].to]);
        }
   if (sum==0){
              if (!--gap[dep[t]]) dep[S]=nodes;
                else ++gap[dep[t]=mindis+1];
                }
    return sum;
} 

void dfs(int s){
     if (s==T) return;
     v[s]=true;
     printf("%d ",s);
     for (int i=head[s];i;i=e[i].next){
         if (!v[e[i].to] && e[i].cap==0)  dfs(e[i].to-n);
                         }
}

void output(){
     memset(v,false,sizeof(v));
     v[0]=true;
     for (int i=1;i<=n;i++)
         if (!v[i]){
            int j=head[i+n];
            if (e[j].cap==1) dfs(i);
            printf("\n");
            }
}

int main(){
    freopen("path3.in","r",stdin);
    freopen("path3.out","w",stdout);
    scanf("%d%d",&n,&m);
    int x,y;
    for (int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        add(x,y+n,1); //x={1..n},y={n+1..2n}
        }
    S=0; T=2*n+1; nodes=T+1; gap[0]=nodes;
    for (int i=1;i<=n;i++) add(S,i,1);
    for (int i=n+1;i<=2*n;i++) add(i,T,1);
    while (dep[S]<nodes) maxflow+=SAP(S,INF);
    output();
    printf("%d\n",n-maxflow);
}
    


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值