最小路径覆盖:有向图的最小路径覆盖为选取最少的路径(路径不相交)能够把图的所有顶点都覆盖(定点不可被重复覆盖)
做法:将有向图变为拆点二分图,然后进行二分图匹配,答案即为n-|最大匹配数|
最小路径可重点覆盖:即路径可相交的路径覆盖
做法:将有向图进行传递闭包后,再进行最小路径覆盖
#include<cstdio> #include<cstring> using namespace std; struct my{ int v; int next; }; const int maxn=800+10; int tu[maxn][maxn],fa; int adj[maxn*2],match[maxn*2]; bool vis[maxn*2]; my bian[maxn*100]; void myinsert(int u,int v){ bian[++fa].v=v; bian[fa].next=adj[u]; adj[u]=fa; } int dfs(int x){ for (int i=adj[x];i;i=bian[i].next){ int v=bian[i].v; if(!vis[v]){ vis[v]=true; if(!match[v]||dfs(match[v])){ match[v]=x; return 1; } } } return 0; } int main(){ int n,m; int u,v; scanf("%d%d",&n,&m); for (int i=1;i<=m;i++){ scanf("%d%d",&u,&v); tu[u][v]=1; } for (int i=1;i<=n;i++) tu[i][i]=1; for (int k=1;k<=n;k++){ for (int i=1;i<=n;i++){ for (int j=1;j<=n;j++){ tu[i][j] |= tu[i][k] && tu[k][j]; } } } for (int i=1;i<=n;i++) tu[i][i]=0; for (int i=1;i<=n;i++){ for (int j=1;j<=n;j++){ if(tu[i][j]) myinsert(i,j+n); } } int ans=n; for (int i=1;i<=2*n;i++){ for (int j=1;j<=2*n;j++) vis[j]=0; if(dfs(i)) ans--; } printf("%d ",ans); return 0; }
输出方案
即为一直在路径上找到无有向边相连的点
#include<cstdio> #include<cstring> using namespace std; struct my{ int v; int next; }; const int maxn=800+10; int tu[maxn][maxn],fa; int adj[maxn*2],match[maxn*2],hide[maxn],vis2[maxn]; bool vis[maxn*2],succ[maxn*2]; my bian[maxn*100]; void myinsert(int u,int v){ bian[++fa].v=v; bian[fa].next=adj[u]; adj[u]=fa; } int dfs(int x){ for (int i=adj[x];i;i=bian[i].next){ int v=bian[i].v; if(!vis[v]){ vis[v]=true; if(!match[v]||dfs(match[v])){ match[v]=x; return 1; } } } return 0; } int main(){ int n,m; int u,v; scanf("%d%d",&n,&m); for (int i=1;i<=m;i++){ scanf("%d%d",&u,&v); tu[u][v]=1; } for (int i=1;i<=n;i++) tu[i][i]=1; for (int k=1;k<=n;k++){ for (int i=1;i<=n;i++){ for (int j=1;j<=n;j++){ tu[i][j] |= tu[i][k] && tu[k][j]; } } } for (int i=1;i<=n;i++) tu[i][i]=0; for (int i=1;i<=n;i++){ for (int j=1;j<=n;j++){ if(tu[i][j]) myinsert(i,j+n); } } int ans=n; for (int i=1;i<=2*n;i++){ for (int j=1;j<=2*n;j++) vis[j]=0; if(dfs(i)) ans--; } int top=0; printf("%d ",ans); for (int i=1;i<=n;i++) succ[match[i]]=true; for (int i=1;i<=n;i++) if(!succ[i]) hide[++top]=i; bool flag=true; while(flag){ flag=false; for (int i=1;i<=ans;i++){ for (int j=1;j<=n;j++){ if(tu[hide[i]][j]) vis2[j]=true; } } for (int i=1;i<=ans;i++){ if(vis2[hide[i]]){ flag=true; while(vis[hide[i]]) hide[i]=match[hide[i]]; } } } for (int i=1;i<=ans;i++) printf("%d ",hide[i]); return 0; }