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

    【题目】1738: 最小路径覆盖问题

    【题解】网络流

    关于输出路径,因为即使有反向弧经过左侧点也一定会改变左侧点的去向,若没连向右侧就会被更新到0,所以不用在意。

    mark记录有入度的右侧点,然后从没入度的右侧点开始把整条路径输出来即可。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn=100000,inf=0x3f3f3f3f;
    int n,m,S,T,d[maxn],q[10010],first[maxn],tot=1,nex[maxn];
    bool mark[maxn];
    struct edge{int from,v,flow;}e[maxn];
    void insert(int u,int v,int w)
    {tot++;e[tot].v=v;e[tot].flow=w;e[tot].from=first[u];first[u]=tot;
     tot++;e[tot].v=u;e[tot].flow=0;e[tot].from=first[v];first[v]=tot;}
    bool bfs()
    {
        memset(d,-1,4*(2*n+3));
        int head=0,tail=1;q[0]=S;d[S]=0;
        while(head<tail)
         {
             int x=q[head++];if(head>10000)head=0;
             for(int i=first[x];i;i=e[i].from)
              if(e[i].flow&&d[e[i].v]==-1)
               {
                   int y=e[i].v;
                   d[y]=d[x]+1;
                   q[tail++]=y;if(tail>10000)tail=0;
               }
         }
        return d[T]!=-1;
    }
    int dinic(int x,int a)
    {
    //    printf("x=%d a=%d
    ",x,a);
        if(x==T||a==0)return a;
        int flow=0,f;
        for(int i=first[x];i;i=e[i].from)
         if(e[i].flow&&d[e[i].v]==d[x]+1&&(f=dinic(e[i].v,min(a,e[i].flow)))>0)
          {
              if(f>0)
             {
                 nex[x]=e[i].v;
                 if(e[i].v-n>0)mark[e[i].v-n]=1;
             }
              e[i].flow-=f;
              e[i^1].flow+=f;
              a-=f;
              flow+=f;
              if(a==0)break;
          }
        return flow;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        S=0,T=2*n+1;
        for(int i=1;i<=m;i++)
         {
             int u,v;
             scanf("%d%d",&u,&v);
             insert(u,v+n,1);
         }
        for(int i=1;i<=n;i++)insert(S,i,1);
        for(int i=n+1;i<=2*n;i++)insert(i,T,1);
        int ans=n;
        while(bfs())ans-=dinic(S,inf);
        for(int i=1;i<=n;i++)if(!mark[i])
         {
             printf("%d ",i);
             int k=i;
             while(nex[k])
              {
                  printf("%d ",nex[k]-n);
                  k=nex[k]-n;
              }
             printf("
    ");
         }
        printf("%d",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    求一些数字字符参数的和(Java)
    《大道至简》第二章 读后感
    华为机试题 简单错误记录
    华为机试 购物单
    华为机试题 提取不重复的整数
    华为机试题 合并表结构
    华为机试 取近似值
    华为机试题 质数因子
    华为机试题 进制转换
    华为机试题 字符串分割
  • 原文地址:https://www.cnblogs.com/onioncyc/p/6713130.html
Copyright © 2011-2022 走看看