zoukankan      html  css  js  c++  java
  • P2764 [网络流24题]最小路径覆盖问题[最大流]

    地址

    这题有个转化,求最少的链覆盖→即求最少联通块。

    设联通块个数$x$个,选的边数$y$,点数$n$个

    那么有 $y=n-x$   即  $x=n-y$

    而n是不变的,目标就是在保证每个点入度、出度不大于1的前提下让选的边尽可能地多。

    下面网络流建模。

    利用二分图匹配建图,左右两点集都包含 n 个点,左点集代表 u 的出度,右点集代表 u 的入度。对于原图中的边 (u,v),从 左边的u点 向 右边的v点 连一条容量为 1 的 边,左点集与超级源点、右点集与超级汇点都分别连一条容量 1 的边,然后从源点做最大流,容量设1保证了我们每个点只流向另外唯一一个点,不会重叠。最大流即为所选边在满足条件下的最多数量。答案就是$n-y$。

    spj那个的话就只要找到每一块的起点,也就是入度为0,这个看代码。找到起点就往后查残量为0的边顺着跑到底就行啦。

    注意,这个只能是对DAP有效。有环的话就不行了,连通块会多余边会被流过,可以画一下。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 typedef pair<int,int> pii;
     5 template<typename T>inline char MIN(T&A,T B){return A<B?A=B,1:0;}
     6 template<typename T>inline char MAX(T&A,T B){return A>B?A=B,1:0;}
     7 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
     8 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
     9 template<typename T>inline T read(T&x){
    10     x=0;char c;while(!isdigit(c=getchar()))if(isalpha(c))return x=(int)c;
    11     while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();return x;
    12 }
    13 const int N=150+7,M=10000+7,INF=0x3f3f3f3f;
    14 int w[M<<1],v[M<<1],Next[M<<1],Head[N<<1],cur[N<<1],dis[N<<1],tot=1,s,t,n,m;
    15 inline void Addedge(int x,int y,int z){
    16     v[++tot]=y,Next[tot]=Head[x],Head[x]=tot,w[tot]=z;
    17     v[++tot]=x,Next[tot]=Head[y],Head[y]=tot,w[tot]=0;
    18 }
    19 #define y v[j]
    20 inline char bfs(){
    21     queue<int> q;q.push(s),memset(dis,0,sizeof dis),dis[s]=1;
    22     for(register int i=1;i<=(n<<1)+2;++i)cur[i]=Head[i];
    23     while(!q.empty()){
    24         int x=q.front();q.pop();
    25         for(register int j=Head[x];j;j=Next[j])if(w[j]&&!dis[y]){
    26             dis[y]=dis[x]+1,q.push(y);
    27             if(y==t)return 1;
    28         }
    29     }
    30     return 0;
    31 }
    32 int dinic(int x,int flow){
    33     if(!flow||x==t)return flow;
    34     int rest=flow,k;
    35     for(register int j=cur[x];j&&rest;cur[x]=j,j=Next[j])if(w[j]&&dis[y]==dis[x]+1){
    36         if(!(k=dinic(y,_min(rest,w[j]))))dis[y]=0;
    37         rest-=k,w[j]-=k,w[j^1]+=k;
    38     }
    39     return flow-rest;
    40 }
    41 #undef y
    42 int x,y,ans;
    43 inline void print(int x){
    44     printf("%d ",x);
    45     for(register int j=Head[x];j;j=Next[j])if(v[j]<s&&!w[j])print(v[j]-n);
    46 }
    47 
    48 int main(){//freopen("tmp.in","r",stdin);freopen("tmp.out","w",stdout);
    49     read(n),read(m);s=2*n+1,t=2*n+2;
    50     for(register int i=1;i<=n;++i)Addedge(s,i,1);
    51     for(register int i=n+1;i<=n*2;++i)Addedge(i,t,1);
    52     for(register int i=1;i<=m;++i)read(x),read(y),Addedge(x,y+n,1);
    53     while(bfs())ans+=dinic(s,INF); ans=n-ans;
    54     for(register int i=n+1;i<s;++i){//  s <==> n*2+1  
    55         int tmp=0;  
    56         for(register int j=Head[i];j;j=Next[j])if(v[j]<=n&&w[j]){tmp=1;break;}
    57         if(!tmp)print(i-n),puts("");
    58     }
    59     printf("%d
    ",ans);
    60     return 0;
    61 }
  • 相关阅读:
    如何为你的Airtest报告自定义名称
    Go打包构建 生成32位64位应用程序 加入前端项目
    DNS解析与DNS缓存清理
    sharepoint2013安装记录
    C# winform自托管WebApi及身份信息加密、Basic验证、Http Message Handler、跨域配置
    IM扫码登录技术专题(四):你真的了解二维码吗?刨根问底、一文掌握!
    IM开发干货分享:万字长文,详解IM“消息“列表卡顿优化实践
    阿里IM技术分享(五):闲鱼亿级IM消息系统的及时性优化实践
    使用oracle序列+oracle定时任务获取每月从1开始的流水码
    为什么我的数据库查询越来越慢
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10356972.html
Copyright © 2011-2022 走看看