zoukankan      html  css  js  c++  java
  • 【题解】 最小路径覆盖问题(网络流)

    最小路径覆盖问题

    考虑最终的那些覆盖路径的样子是什么,显然是很多点和很多链(废话),但是学过生物必修一肽链和蛋白质的人都能发现,路径条数=(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('
    ');
    	    }
          }
    }
    
    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
    ",ans);      
          return 0;
    }
    
    
  • 相关阅读:
    Dynamics CRM修改密码界面
    Dynamics CRM新加了组织后提示数据加密错误的解决方法
    ADFS修改默认访问端口
    Dynamics CRM与ADFS安装到同一台服务器后ADFS服务与Dynamics CRM沙盒服务冲突提示808端口占用问题
    Dynamics CRM各个版本的元数据浏览解决方案
    Dynamics CRM9.0安装CRM的时候提示Microsoft.Crm.Setup.Server.RegisterSandboxServiceAction操作失败
    IIS误删了默认网站,恢复方法
    grafana配置邮件告警
    Git连接Gitlab并提交内容
    docker自定义bridge
  • 原文地址:https://www.cnblogs.com/winlere/p/11237210.html
Copyright © 2011-2022 走看看