例1
有一张有向图,一些伞兵可以落在任意位置,沿着有向边往前走。注意一条路仅能被一个伞兵经过
问最少派出多少个伞兵
题解
这是一个最小(不相交)路径覆盖问题,因为从每个点出发,下一步最多经过一条边,因此可以用二分匹配解决(可以想见)
code
#include<bits/stdc++.h> //二分匹配
#define ll long long
using namespace std;
int n,m,p;
bool g[505][505],reserved[505];
int ans[505];
bool dfs(int now){
for(int i=1;i<=n;i++){
if(!reserved[i]&&g[now][i]){
reserved[i]=1;
if(ans[i]==-1||dfs(ans[i])){
ans[i]=now;
return 1;
}
}
}
return 0;
}
int main(){
int t;cin>>t;
while(t--){
cin>>n>>m;
memset(g,0,sizeof(g));
memset(ans,-1,sizeof(ans));
for(int i=1,x,y,z;i<=m;i++){
scanf("%d%d",&x,&y);
g[x][y]=1;
}
int anss=0;
for(int i=1;i<=n;i++){
memset(reserved,0,sizeof(reserved));
if(dfs(i)) anss++;
}
cout<<n-anss<<endl;
}
return 0;
}
例2
缩点后,转化成最小路径覆盖问题
code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct Edge{
int to,nex;
}e[2][100005];
int head[2][10004],q[11005],f[11005],a[10005],va[10005],dp[10005];
int n,m,cnt[2],t;
bool vis[10005];
int x[100005],y[100005];
vector<int>v[10005];
int anss;
int match[5005]; //下标是配对的b方 值为对应的a方
bool reserve_b[5005];
void init(){
memset(head,0,sizeof(head));
memset(vis,0,sizeof(vis));
memset(match,0,sizeof(match));
for(int i=1;i<=n;i++)v[i].clear(); //
t=0;
cnt[0]=cnt[1]=0;
}
void add(int u,int v){
cnt[0]++;
e[0][cnt[0]].to=v;
e[0][cnt[0]].nex=head[0][u];
head[0][u]=cnt[0];
}
void add2(int u,int v){
cnt[1]++;
e[1][cnt[1]].to=v;
e[1][cnt[1]].nex=head[1][u];
head[1][u]=cnt[1];
}
void dfs1(int now){
vis[now]=1;
for(int i=head[0][now];i;i=e[0][i].nex){
int x=e[0][i].to;
if(!vis[x]) dfs1(x);
}
q[++t]=now;
}
void dfs2(int now,int y){
vis[now]=0; f[now]=y;
for(int i=head[1][now];i;i=e[1][i].nex){
int x=e[1][i].to;
if(vis[x]) dfs2(x,y);
}
}
//二分图匹配
bool dfs(int now){
for(int i=0;i<v[now].size();i++){
int x=v[now][i];
if(!reserve_b[x]){
reserve_b[x]=1;
if(!match[x]||dfs(match[x])){ //b无配对 或者 b的原配可以找到新的配对
match[x]=now; //则令x为b的配对
return 1; //x找到了配对
}
}
}
return 0;
}
int main(){
int T;cin>>T;
while(T--){
cin>>n>>m;
init();
for(int i=1;i<=m;i++){
scanf("%d%d",&x[i],&y[i]);
add(x[i],y[i]);
add2(y[i],x[i]);
}
for(int i=1;i<=n;i++){
if(!vis[i]){
dfs1(i);
}
}
for(int i=n;i>=1;i--){
if(vis[q[i]]){
dfs2(q[i],q[i]);
}
}
for(int i=1;i<=m;i++){
if(f[x[i]]!=f[y[i]]) v[f[x[i]]].push_back(f[y[i]]);
}
set<int>st;
for(int i=1;i<=n;i++){
st.insert(f[i]);
va[f[i]]+=a[i];
}
anss=0;
for(auto i=st.begin();i!=st.end();i++){ //a方
memset(reserve_b,0,sizeof(reserve_b)); //不加会错
if(dfs(*i)) anss++; //ai配对成功后配对数++,虽然可能更换配对,但是保证ai一定有配对
}
cout<<st.size()-anss<<endl;
}
return 0;
}