学一发有向无环图(DAG)的最小路径覆盖。大佬传送门
首先,DAG中的最小可相交路径覆盖可以转化成最小不相交路径覆盖:先用floyd求出原图的传递闭包,即如果
x
到
然后对于最小不相交路径覆盖,可以把每个点
V
拆成
回到这题,发现直接求出DAG的最小不相交路径覆盖就行了。至于输出路径,用一个并查集来记录即可。
附上AC代码:
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int N=210;
struct side{
int to,nt;
}s[12010];
int n,m,num,h[N],x,y,sy[N],ans,f[N],fx,fy;
vector <int> a[N];
bool b[N];
inline void add(int x,int y){
s[++num]=(side){y,h[x]},h[x]=num;
}
inline bool so(int x){
for (int i=h[x]; i; i=s[i].nt)
if (!b[s[i].to]){
b[s[i].to]=1;
if (!sy[s[i].to]||so(sy[s[i].to])) return sy[s[i].to]=x,1;
}
return 0;
}
inline int gf(int x){return x==f[x]?x:f[x]=gf(f[x]);}
int main(void){
scanf("%d%d",&n,&m);
for (int i=1; i<=m; ++i) scanf("%d%d",&x,&y),add(x,y);
for (int i=1; i<=n; ++i){
memset(b,0,sizeof b);
if (so(i)) ++ans;
}
for (int i=1; i<=n; ++i) f[i]=i;
for (int i=1; i<=n; ++i)
if (sy[i]&&f[i]!=f[sy[i]]) fx=gf(i),fy=gf(sy[i]),f[fx]=fy;
for (int i=1; i<=n; ++i) a[f[i]].push_back(i);
for (int i=1; i<=n; ++i)
if (a[i].size()){
for (int j=0; j<a[i].size(); ++j) printf("%d ",a[i][j]);
putchar('\n');
}
return printf("%d\n",n-ans),0;
}