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;
}

原文地址:https://www.cnblogs.com/OvOq/p/14751132.html