LUOGU P2764 最小路径覆盖问题 (最小路径点覆盖)

解题思路

有向图最小路径点覆盖问题,有这样的结论就是有向图最小路径点覆盖等于n-拆点二分图中最大匹配。具体怎么证明不太知道。。输出方案时找到所有左部未匹配的点一直走$match​$就行了。



#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>

using namespace std;
const int MAXN = 305;
const int MAXM = 6005;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}

int n,m,a[MAXN][MAXN],ans,match[MAXN],num,vis[MAXN],go[MAXM];
bool suc[MAXN];

bool dfs(int x){
    for(register int i=n+1;i<=2*n;i++)if(a[x][i]){
        if(vis[i]==num) continue;vis[i]=num;
        if(!match[i] || dfs(match[i])) {match[i]=x;return true;}
    }
    return false;
}

void out(int x){
    if(!x) return;
    out(x/10);
    putchar('0'+x%10);
}

int main(){
    n=rd(),m=rd();int x,y;
    for(register int i=1;i<=m;i++){
        x=rd(),y=rd();
        a[x][y+n]=1;
    }
    for(register int i=1;i<=n;i++)
        num++,ans+=dfs(i);
    ans=n-ans;
    for(register int i=n+1;i<=2*n;i++) suc[match[i]]=1;
    for(register int i=1;i<=n;i++)
        if(!suc[i]) {
            int cnt=0,now=i;
            while(now) {go[++cnt]=now;now=match[now+n];}
            for(register int j=cnt;j;j--) out(go[j]),putchar(' ');
            putchar('\n');
        }
    cout<<ans<<endl;
    return 0;
}
View Code

 

 

posted @ 2018-10-08 15:40  Monster_Qi  阅读(121)  评论(0编辑  收藏  举报