【题解】 最小路径覆盖问题(网络流)

最小路径覆盖问题

考虑最终的那些覆盖路径的样子是什么,显然是很多点和很多链(废话),但是学过生物必修一肽链和蛋白质的人都能发现,路径条数=\(n-m'\)\(n\)是点的个数,\(m'\)是选出来的边的条数。

这里的\(n\)是个定值,问题转变了选出最多的边\(m'\),使得选出的边不存在共同的起点或终点。

也就是说,一个点可以同时作为起点和终点,但是不能被两条边同时连接。考虑边是有起点的,也就是说,一个终点可以且仅可以和一个起点匹配,每成功匹配到一个就说明可以选出一条边

起点终点匹配=二分图匹配=最大流=\(m'\)

总结起来,可以得到一个方法:选边=匹配起点和终点

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>

using namespace std;  typedef long long ll;
inline int qr(){
      register int ret=0,f=0;
      register char c=getchar();
      while(c<48||c>57)f|=c==45,c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return f?-ret:ret;
}

int cnt=1;
const int inf=0x3f3f3f3f;
int S,T,m,n;

struct E{
      int to,nx,w;
      E(){to=nx=w=0;}
      E(const int&a,const int&b,const int&c){to=a;nx=b;w=c;}
}e[48005];
int head[355];
inline void add(const int&fr,const int&to,const int&w,const int&f=1){
      e[++cnt]=E(to,head[fr],w);
      head[fr]=cnt;
      if(f) add(to,fr,0,0);
}


const int maxn=355;
int sum=0;
queue < int > q;
int d[maxn],cur[maxn];
inline bool bfs(){
      for(register int t=1;t<=n+n+2;++t) d[t]=0,cur[t]=head[t];
      d[S]=1;q.push(S);
      while(q.size()){
        register int now=q.front();
        q.pop();
        for(register int t=head[now];t;t=e[t].nx){
          if(e[t].w>0&&d[e[t].to]==0){
            d[e[t].to]=d[now]+1;
            q.push(e[t].to);        
          }
        }
      }
      return d[T];
      
}

int dfs(const int&now,int fl){
      if(now==T||fl==0)return fl;
      register int ret=0;
      for(register int&t=cur[now];t;t=e[t].nx){
        if(e[t].w>0&&d[e[t].to]==d[now]+1){
          int d=dfs(e[t].to,min(e[t].w,fl));
          e[t].w-=d;e[t^1].w+=d;ret+=d;fl-=d;
        }
      }
      return ret;
}


inline int dinic(){
      int ret=0;
      while(bfs())ret+=dfs(S,inf);
      return ret;
}

namespace getans{
#define pb push_back
      vector < vector < int > > ve;
      const int maxn=155;
      int r[maxn];
      int dr[maxn];
      inline void add(int fr,int to){
        r[to]=fr;
        ++dr[to];++dr[fr];
      }
      int n;
      inline void main(const int&a){
        vector < int > temp;n=a;
        for(register int t=1;t<=n;++t){
          if(dr[t]==1&&r[t]){
            vector < int > ().swap(temp);
            int now=t;
            while(r[now]) temp.pb(now),now=r[now];
            temp.pb(now);reverse(temp.begin(),temp.end());
            ve.pb(temp);
          }
          if(!dr[t]){
            vector < int > (t).swap(temp);
            ve.pb(temp);
          }
        }
        for(auto t:ve){
          for(auto f:t)
            printf("%d ",f);
          putchar('\n');
        }
      }
}

int main(){
      
      n=qr();m=qr();
      S=n+n+1;T=n+n+2;
      for(register int t=1;t<=n;++t)
        add(S,t,1),add(t+n,T,1);
      for(register int t=1;t<=m;++t){
        register int t1=qr(),t2=qr();
        add(t1,t2+n,1);
      }
      int ans=n-dinic();
      for(register int t=1;t<=n;++t)
        for(register int i=head[t];i;i=e[i].nx)
          if(e[i].w==0&&e[i].to>=n&&e[i].to<=n+n){
            getans::add(t,e[i].to-n);
            break;
          }
      getans::main(n);
      printf("%d\n",ans);      
      return 0;
}

猜你喜欢

转载自www.cnblogs.com/winlere/p/11237210.html
今日推荐