AcWing——2549. 估计人数(最小重复路径点覆盖)
思路:
最小路径点覆盖
DAG :用最少的互不相交的路径将所有点覆盖
拆点:i ==> i出点 i'入点
将原图里的每条路径 转化到新图里
1.路径 匹配
2.路径终点 左部非匹配
让左侧非匹配点最多 <=>左侧匹配点最多 <=>找最大匹配
最小路径重复点覆盖:用最少的路径将所有点覆盖
1.求g传递闭包g'
2.g的最小路径重复点覆盖==g'的最小路径覆盖
代码:
int s[30][30],n,m,mp[30][30],idx;
int g[210][210];
bool st[maxn];
int mat[maxn];
bool Find(int x){
for(int i=1;i<=idx;i++)
if(g[x][i]&&!st[i]){
st[i]=1;
int t=mat[i];
if(t==0||Find(t)){
mat[i]=x;
return 1;
}
}
return 0;
}
int main() {
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%1d",&s[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(s[i][j]==1) mp[i][j]=++idx;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(s[i][j]==1){
if(i+1<=n&&s[i+1][j]==1) g[mp[i][j]][mp[i+1][j]]=1;
if(j+1<=m&&s[i][j+1]==1) g[mp[i][j]][mp[i][j+1]]=1;
}
}
for(int k=1;k<=idx;k++)
for(int i=1;i<=idx;i++)
for(int j=1;j<=idx;j++)
if(g[i][k]&&g[k][j]) g[i][j]=1;
int res=0;
for(int i=1;i<=idx;i++){
memset(st,0,sizeof st);
if(Find(i)) res++;
}
cout<<idx-res<<endl;
return 0;
}