[网络流24题]最小路径覆盖问题
对于一个路径覆盖会有两个性质:
1.每个点属于且只属于一条路径;
2.在每条路径中,除终点外,每个点只有一条边可以通向路径中的另外一个点。
所以可以把每个点拆成两个点,一个是起始点,一个是目标点,建立二分图模型。
二分图中的任何一种匹配都对应着一种路径覆盖方案。
若匹配数为零,那么路径数=总点数,每增加一个匹配,就会减少一条路径,所以有
最小路径覆盖数=总点数-最大匹配数
再在匹配过程中记录路径最后输出即可。
#include<complex> #include<cstdio> using namespace std; const int INF=0x3f3f3f3f; const int N=401,M=6007; struct node{ int v,f,nxt; }e[M<<1]; int n,m,Enum=1,s,t,ans; int front[N],cur[N],deep[N],path[N]; int q[N]; bool vis[N]; int qread() { int x=0; char ch=getchar(); while(ch<'0' || ch>'9')ch=getchar(); while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} return x; } void Insert(int u,int v) { e[++Enum].v=v;e[Enum].f=1;e[Enum].nxt=front[u];front[u]=Enum; e[++Enum].v=u;e[Enum].nxt=front[v];front[v]=Enum; } bool bfs() { for(int i=0;i<=t;i++) { deep[i]=0; cur[i]=front[i]; } int head=1,tail=0,u,v; deep[s]=1;q[++tail]=s; while(head<=tail) { u=q[head++]; for(int i=front[u];i;i=e[i].nxt) { v=e[i].v; if(!deep[v] && e[i].f) { deep[v]=deep[u]+1; if(v==t)return 1; q[++tail]=v; } } } return 0; } int dfs(int x,int cur_flow) { if(x==t)return cur_flow; int rest=cur_flow,v; for(int &i=cur[x];i;i=e[i].nxt) { v=e[i].v; if(deep[v]==deep[x]+1 && e[i].f && rest) { int new_flow=dfs(v,min(e[i].f,rest)); e[i].f-=new_flow; e[i^1].f+=new_flow; rest-=new_flow; if(new_flow)path[x]=v-n; if(!rest)return cur_flow; } } deep[x]=0; return cur_flow-rest; } void Dinic() { while(bfs()) ans+=dfs(s,INF); } void print(int x) { if(!x)return; printf("%d ",x); vis[x]=1; print(path[x]); } int main() { scanf("%d%d",&n,&m); s=0;t=n+n+1; int u,v; for(int i=1;i<=m;i++) { u=qread();v=qread(); Insert(u,v+n); } for(int i=1;i<=n;i++) { Insert(s,i); Insert(i+n,t); } Dinic(); for(int i=1;i<=n;i++) if(!vis[i]) { print(i); puts(""); } printf("%d\n",n-ans); return 0; }