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

    题面

    https://www.luogu.org/problem/P2764

    题解

    原谅当年的我太弱,把$dinic$拼错。

    upd:我发现我当年判边在不在最大流上也是假的。应该看$w[i]是否为0$。

    upd:应该是有必要补说一下的,一开始,每个点自成一个路径,然后一个合法的匹配就是把两条路径合二为一,路径数$-1$,所以边可以是有向的。并且不能自己和自己连边。

    最后的路径数是$n-G.dinic()$

    #include<cstdio>
    #include<iostream>
    #define ri register int
    #define N 20000
    
    using namespace std;
    int n,m;
    
    int head[N],cnt=1;
    int dep[N],que[N],nex[N],pre[N];
    int to[7*N],nxt[7*N],wei[7*N],cur[N];
    bool inq[N],vis;
    
    void add(int u,int v,int w) {
      ++cnt;
      nxt[cnt]=head[u];
      to[cnt]=v;
      wei[cnt]=w;
      head[u]=cnt;
    }
    
    bool bfs() {
      for (ri i=1;i<=2*n+2;i++) dep[i]=987654321,cur[i]=head[i],inq[i]=0;
      que[1]=2*n+1; dep[2*n+1]=1; inq[2*n+1]=1;
      int tail=1,hd=1;
      while (tail<=hd) {
        int x=que[tail];
        tail++;
        inq[x]=0;
        for (ri i=head[x];i;i=nxt[i]) if (dep[x]+1<dep[to[i]] && wei[i]) {
          dep[to[i]]=dep[x]+1;
          if (!inq[to[i]]) que[++hd]=to[i],inq[to[i]]=1;
        }
      }
      return dep[2*n+2]<=n;
    }
    
    int dfs(int x,int mi) {
      if (x==2*n+2) {
        vis=1;
        return mi;
      }
      int used=0;
      int rlow;
      for (ri i=cur[x];i;i=nxt[i])  {
        cur[x]=i;
        if (wei[i] && dep[to[i]]==dep[x]+1) {
            rlow=dfs(to[i],min(mi-used,wei[i]));
            if (rlow) {
              if (1<=x && x<=n && n<to[i] && to[i]<=2*n) {
                nex[x]=to[i]-n;
                pre[to[i]-n]=x;
              }
              used+=rlow;
              wei[i]-=rlow;
              wei[i^1]+=rlow;
              if (used==mi) return used;
            }
        }
      }
      return used;
    }
    
    void dicnic(){
      while (bfs()) {
        vis=1;
        while (vis) {
          vis=0;
          dfs(2*n+1,0x3f3f3f3f);
        }
      }
    }
    
    void print(int x) {
      printf("%d ",x);
      if (nex[x]) print(nex[x]);
    }
    
    int main(){
      int u,v;
      scanf("%d %d",&n,&m);
      for (ri i=1;i<=m;i++) {
        scanf("%d %d",&u,&v);
        add(u,n+v,1); add(n+v,u,0);
      }
      for (ri i=1;i<=n;i++) add(2*n+1,i,1),add(i,2*n+1,0);
      for (ri i=n+1;i<=2*n;i++) add(i,2*n+2,1),add(2*n+2,i,0);
      dicnic();
      int ans=0;
      for (ri i=1;i<=n;i++) if (!pre[i]) print(i),puts(""),ans++;
      cout<<ans<<endl;
    }
  • 相关阅读:
    CF44G Shooting Gallery KDtree
    UVA12297 Super Poker 矩阵快速幂
    一些刷题的OJ
    关于博客园里的代码那些事
    Linux高并发网络编程开发——epoll-udp
    Linux高并发网络编程开发——tcp状态转换-select-poll
    Linux高并发网络编程开发——tcp三次握手-并发
    Linux高并发网络编程开发——网络编程基础-socket
    Linux系统编程——线程同步
    Linux系统编程——守护进程+线程
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11285906.html
Copyright © 2011-2022 走看看