题目:最小路径覆盖问题
update 2021/11/11 :
用最大流又写了一次。
也是先拆点,S和xi相连,xi和yi相连,yi和T相连,边权都为1。
跑完最大流后,xi->yi的边权若为0,则可说明这两点相连。
#include<bits/stdc++.h>
using namespace std;
#define maxn 300
#define maxm 15000
#define read(x) scanf("%d",&x)
#define inf (1<<30)
struct Edge{
int x,y,z;
Edge() {}
Edge(int _x,int _y,int _z) {x=_x,y=_y,z=_z;}
};
int n,m,s,t;
int h[maxn+5],nxt[maxm+5],cnt=-1;
Edge e[maxm+5];
void addedge(int x,int y,int z) {
e[++cnt]=Edge(x,y,z);
nxt[cnt]=h[x];
h[x]=cnt;
}
int d[maxn+5];
queue<int> que;
int bfs() {
memset(d,0,sizeof(d));
d[s]=1;
que.push(s);
while(!que.empty()) {
int x=que.front();
que.pop();
for(int i=h[x];~i;i=nxt[i]) {
int y=e[i].y,z=e[i].z;
if(d[y]||z==0) continue;
d[y]=d[x]+1;
que.push(y);
}
}
return d[t];
}
int cur[maxn+5];
int dfs(int x,int w) {
if(x==t) return w;
for(int& i=cur[x];~i;i=nxt[i]) {
int y=e[i].y,z=e[i].z;
if(0==z||d[y]!=d[x]+1) continue;
int Min=dfs(y,min(w,z));
if(Min>0) {
e[i].z-=Min,e[i^1].z+=Min;
return Min;
}
}
return 0;
}
int dinic() {
int ans=0;
while(bfs()) {
for(int i=s;i<=t;i++) cur[i]=h[i];
while(int x=dfs(s,inf)) ans+=x;
}
return ans;
}
int to[maxn+5],fa[maxn+5];
void print() {
for(int i=0;i<=cnt;i++) {
int x=e[i].x,y=e[i].y,z=e[i].z;
if(1<=x&&x<=n&&n+1<=y&&y<=2*n&&z==0) { //只找从 xi -> yi ,剩余流量为0的边
to[x]=y-n,fa[y-n]=to[x];
}
}
for(int i=1;i<=n;i++) {
if(fa[i]==0) {
int x=i;
while(x) {
printf("%d ",x);
x=to[x];
}
printf("\n");
}
}
}
int main() {
memset(h,-1,sizeof(h));
memset(nxt,-1,sizeof(nxt));
read(n),read(m);
for(int i=1;i<=m;i++) {
int x,y;
read(x),read(y);
addedge(x,n+y,1);
addedge(n+y,x,0);
}
s=0,t=2*n+1;
for(int i=1;i<=n;i++) {
addedge(s,i,1);
addedge(i,s,0);
addedge(i+n,t,1);
addedge(t,i+n,0);
}
int ans=dinic();
print();
printf("%d",n-ans);
return 0;
}
思路:
把每个点拆成两个点,其中一个作为入点,另一个作为出点。
然后对于这个二分图求最大匹配输出。
之前因为int没加返回值,系统开了O2优化RE了好久。
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define maxn 150
#define maxm 6000
#define read(x) scanf("%d",&x);
int n,m;
vector<int> g[2*maxn+5];
void readin() {
read(n);
read(m);
for(int i=1; i<=m; i++) {
int x,y;
read(x);
read(y);
g[x].push_back(y+n);
}
}
int use[maxn*2+5],match[maxn*2+5];
int dfs(int x) {
if(use[x]) return false;
use[x]=true;
for(int i=0; i<g[x].size(); i++) {
int y=g[x][i];
if(!match[y]||dfs(match[y])) {
match[x]=y;
match[y]=x;
return true;
}
}
return false;
}
void slv() {
for(int i=1; i<=n; i++) {
dfs(i);
memset(use,0,sizeof(use));
}
}
void print() {
int ans=0;
for(int i=1;i<=n;i++) {
if(use[i]) continue;
ans++;
int x=i+n;
do{
x-=n;
use[x]=true;
printf("%d ",x);
} while(x=match[x]);
printf("\n");
}
printf("%d\n",ans);
}
int main() {
readin();
slv();
print();
return 0;
}