最小路径覆盖问题
考虑最终的那些覆盖路径的样子是什么,显然是很多点和很多链(废话),但是学过生物必修一肽链和蛋白质的人都能发现,路径条数=(n-m'),(n)是点的个数,(m')是选出来的边的条数。
这里的(n)是个定值,问题转变了选出最多的边(m'),使得选出的边不存在共同的起点或终点。
也就是说,一个点可以同时作为起点和终点,但是不能被两条边同时连接。考虑边是有起点的,也就是说,一个终点可以且仅可以和一个起点匹配,每成功匹配到一个就说明可以选出一条边。
起点终点匹配=二分图匹配=最大流=(m')
总结起来,可以得到一个方法:选边=匹配起点和终点
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
int cnt=1;
const int inf=0x3f3f3f3f;
int S,T,m,n;
struct E{
int to,nx,w;
E(){to=nx=w=0;}
E(const int&a,const int&b,const int&c){to=a;nx=b;w=c;}
}e[48005];
int head[355];
inline void add(const int&fr,const int&to,const int&w,const int&f=1){
e[++cnt]=E(to,head[fr],w);
head[fr]=cnt;
if(f) add(to,fr,0,0);
}
const int maxn=355;
int sum=0;
queue < int > q;
int d[maxn],cur[maxn];
inline bool bfs(){
for(register int t=1;t<=n+n+2;++t) d[t]=0,cur[t]=head[t];
d[S]=1;q.push(S);
while(q.size()){
register int now=q.front();
q.pop();
for(register int t=head[now];t;t=e[t].nx){
if(e[t].w>0&&d[e[t].to]==0){
d[e[t].to]=d[now]+1;
q.push(e[t].to);
}
}
}
return d[T];
}
int dfs(const int&now,int fl){
if(now==T||fl==0)return fl;
register int ret=0;
for(register int&t=cur[now];t;t=e[t].nx){
if(e[t].w>0&&d[e[t].to]==d[now]+1){
int d=dfs(e[t].to,min(e[t].w,fl));
e[t].w-=d;e[t^1].w+=d;ret+=d;fl-=d;
}
}
return ret;
}
inline int dinic(){
int ret=0;
while(bfs())ret+=dfs(S,inf);
return ret;
}
namespace getans{
#define pb push_back
vector < vector < int > > ve;
const int maxn=155;
int r[maxn];
int dr[maxn];
inline void add(int fr,int to){
r[to]=fr;
++dr[to];++dr[fr];
}
int n;
inline void main(const int&a){
vector < int > temp;n=a;
for(register int t=1;t<=n;++t){
if(dr[t]==1&&r[t]){
vector < int > ().swap(temp);
int now=t;
while(r[now]) temp.pb(now),now=r[now];
temp.pb(now);reverse(temp.begin(),temp.end());
ve.pb(temp);
}
if(!dr[t]){
vector < int > (t).swap(temp);
ve.pb(temp);
}
}
for(auto t:ve){
for(auto f:t)
printf("%d ",f);
putchar('
');
}
}
}
int main(){
n=qr();m=qr();
S=n+n+1;T=n+n+2;
for(register int t=1;t<=n;++t)
add(S,t,1),add(t+n,T,1);
for(register int t=1;t<=m;++t){
register int t1=qr(),t2=qr();
add(t1,t2+n,1);
}
int ans=n-dinic();
for(register int t=1;t<=n;++t)
for(register int i=head[t];i;i=e[i].nx)
if(e[i].w==0&&e[i].to>=n&&e[i].to<=n+n){
getans::add(t,e[i].to-n);
break;
}
getans::main(n);
printf("%d
",ans);
return 0;
}