• 【Luogu】P2764最小路径覆盖(拆点求最大匹配)


      题目链接

      这个……学了一条定理

      最小路径覆盖=原图总点数-对应二分图最大匹配数

      这个对应二分图……是什么呢?

      就是这样

      

      这是原图

      

      这是拆点之后对应的二分图。

      

       然后咱们的目标就是从这张图上跑出个最大流来,然后用原图的总点数减去就是答案。

      至于记录路径……我发现有一个规律是可以在Dinic跑DFS的时候记。

      别的我不知道了。因为我只会Dinic。

      代码如下。

      

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    #include<queue>
    #include<cstdlib>
    #define maxn 3000
    #define maxm 60000
    using namespace std;
    inline long long read(){
        long long num=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            num=num*10+ch-'0';
            ch=getchar();
        }
        return num*f;
    }
    
    inline int count(int i){    return i&1?i+1:i-1;    }
    
    struct Edge{
        int next,to,val;
    }edge[maxm*5];
    int head[maxn*3],num;
    inline void addedge(int from,int to,int val){
        edge[++num]=(Edge){head[from],to,val};
        head[from]=num;
    }
    inline void add(int from,int to,int val){
        addedge(from,to,val);
        addedge(to,from,0);
    }
    
    bool vis[maxn];
    int dfn[maxn];
    int list[maxn*3];
    int Start,End;
    int road[maxn*3];
    int n,m;
    bool flag;
    
    bool bfs(){
        memset(vis,0,sizeof(vis));
        queue<int> q; dfn[Start]=1; vis[Start]=1;    q.push(Start);
        while(!q.empty()){
            int from=q.front();    q.pop();
            for(int i=head[from];i;i=edge[i].next){
                int to=edge[i].to;
                if(vis[to]||edge[i].val<=0)    continue;
                vis[to]=1;
                dfn[to]=dfn[from]+1;
                q.push(to);
            }
        }
        return vis[End];
    }
    
    int dfs(int x,int val){
        //printf("%d %d
    ",x,val);
        if(val==0||x==End)    return val;
        vis[x]=1;    int flow=0;
        for(int &i=list[x];i;i=edge[i].next){
            int to=edge[i].to;
            if(vis[to]||dfn[to]!=dfn[x]+1||edge[i].val<=0)    continue;
            int now=dfs(to,min(val,edge[i].val));
            val-=now;    edge[i].val-=now;    flow+=now;    edge[count(i)].val+=now;
            if(val<=0){
                road[x]=to;
                break;
            }
        }
        if(flow!=val)    dfn[x]=-1;
        return flow;
    }
    
    int maxflow(){
        int ans=0;
        while(bfs()){
            memset(vis,0,sizeof(vis));
            for(int i=Start;i<=End;++i)    list[i]=head[i];
            int now=dfs(Start,0x7fffffff);
            if(!now)    break;
            ans+=now;
        }
        return ans;
    }
    
    int main(){
        n=read(),m=read();End=n*2+1;
        for(int i=1;i<=n;++i){
            add(Start,i,1);
            add(i+n,End,1);
        }
        for(int i=1;i<=m;++i){
            int from=read(),to=read();
            add(from,to+n,1);
        }
        int ans=maxflow();
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;++i){
            if(road[i]==0)    continue;
            int now=i;
            while(now!=End&&now){
                printf("%d ",now>n?now-=n:now);
                int x=road[now];    road[now]=0;
                now=x;
            }
            printf("
    ");
        }
        printf("%d",n-ans);
        return 0;
    }
  • 相关阅读:
    微人事项目-mybatis-持久层
    通过外键连接多个表
    springioc
    Redis 消息中间件 ServiceStack.Redis 轻量级
    深度数据对接 链接服务器 数据传输
    sqlserver 抓取所有执行语句 SQL语句分析 死锁 抓取
    sqlserver 索引优化 CPU占用过高 执行分析 服务器检查
    sql server 远程备份 bak 删除
    冒泡排序
    多线程 异步 beginInvoke EndInvoke 使用
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/8202364.html
Copyright © 2020-2023  润新知