洛谷 P2764 最小路径覆盖问题 题解--zhengjun
思路
只需要用二分图匹配,每一次连接了一对匹配,相当于合并了两条路径(单个点也认为是路径),所以要让路径总数最小,就要让匹配的数量最大,由于是路径,所以每个点的入点和出点都最多只能连两条边。
代码
#include<bits/stdc++.h>
using namespace std;typedef long long ll;const int N=3e2+10,M=1.2e4+10;
int T,n,m,s,t,head[N],kk=1,d[N],cur[N],ans,nex[N];bool vis[N];struct edges{int to,c,nex;}edge[M];
void add(int u,int v,int c){edge[++kk]={v,c,head[u]};head[u]=kk;edge[++kk]={u,0,head[v]};head[v]=kk;}
bool bfs(){
memset(d,-1,sizeof d);d[s]=0;cur[s]=head[s];queue<int>q;for(q.push(s);!q.empty();q.pop()){
int u=q.front();for(int i=head[u],v;v=edge[i].to,i;i=edge[i].nex)
if(d[v]==-1&&edge[i].c)d[v]=d[u]+1,cur[v]=head[v],q.push(v);
}return d[t]!=-1;
}
int dfs(int u,int lim=1e9){
if(u==t)return lim;int flow=0;for(int i=head[u],v;v=edge[i].to,i&&flow<lim;i=edge[i].nex){
cur[u]=i;if(d[v]!=d[u]+1||!edge[i].c)continue;int f=dfs(v,min(lim-flow,edge[i].c));
if(!f)d[v]=-1;edge[i].c-=f;edge[i^1].c+=f;flow+=f;
}return flow;
}
int dinic(){int maxflow=0;while(bfs())maxflow+=dfs(s);return maxflow;}
int main(){
scanf("%d%d",&n,&m);for(int i=1,u,v;i<=m;i++)scanf("%d%d",&u,&v),add(u,v+n,1);
s=0;t=n+n+1;for(int i=1;i<=n;i++)add(s,i,1),add(i+n,t,1);ans=n-dinic();
for(int u=1;u<=n;u++)for(int i=head[u],v;v=edge[i].to,i;i=edge[i].nex)if(v>n&&!edge[i].c)nex[u]=v-n;
for(int i=1;i<=n;i++){if(vis[i])continue;for(int j=i;j;j=nex[j])printf("%d ",j),vis[j]=1;puts("");}cout<<ans;
}