【网络流】最小路径覆盖

最小边覆盖=最大独立集=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);
}
    


你可能感兴趣的:(【网络流】最小路径覆盖)