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; }