1 条题解

  • 2
    @ 2022-2-10 18:52:01

    此题重点在二分图的建图。

    考虑放置木板的决策,由于可以重复覆盖,所以对于两个可以选择的区间 a,b**,若 b** 被 a** 覆盖,那么选择 a** 一定优于选择 b**。

    解释如图:泥地为黄色,草地为绿色

    显然,木板 A 一定比木板 B 更优,因为橙色部分可以重复覆盖。

    由此易得所有的木板两头都是没有泥地的:若有,则增长此木板一定比原方案更优。

    得到这个结论,我们可以先预处理出所有可能放置木板的位置,也就是在每行每列连续的泥地的位置。如图所示:所有木板可能放置的位置是下图的十个。

    对于每一个点,要么被横着覆盖,要么被竖着覆盖。举例来讲,(3,3)** 在行上会被横木板 3覆盖,在列上会被竖木板 4 覆盖。而我们要让所有的点都被覆盖,也就是需要满足下图所示的所有条件:

    我们需要选出最少的木板满足这样的若干个约束条件。我们把每一个泥地看成一条边,左端点为其对应的横木板,右端点为其对应的竖木板。 显然这是一个二分图,左边全部为横木板,右边全部为竖木板。

    考虑我们 放置一个木板 ,相当于满足所有包含它的约束条件, 也就是将其所连的边进行染色 。 而对于每一个泥地(也就是边), 如果它被染色,就证明这个格子的约束条件已被满足

    所以这个问题转化为:一次操作可以选择一个点,将所连的边染色,目的是让所有边被染色。

    即为二分图最小点覆盖。

    而最小点覆盖等于最大匹配,故建图跑匈牙利即可。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    int cnt1,cnt2;
    bool a[1002][1002];
    int match[1002];
    int ans;
    bool visit[1002];
    bool dfs(int x){
    	for(int i=1;i<=cnt2;i++){
    		if(a[x][i]&&!visit[i]){
    			visit[i]=1;
    			if(!match[i]||dfs(match[i])){
    				match[i]=x;
    				return 1;
    			}
    		}
    	}
    	return 0;
    }
    char ch[1002][1002];
    int h[1002][1002];
    int c[1002][1002];
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++){//统计横向木板 
    		cin>>ch[i]+1;
    		for(int j=1;j<=m;j++){
    			if(ch[i][j]=='*'){
    				if(j==1||ch[i][j-1]!='*'){
    					h[i][j]=++cnt1;
    				}
    				else h[i][j]=cnt1;
    			}
    		}
    	}
    	for(int i=1;i<=m;i++){//统计竖向木板 
    		for(int j=1;j<=n;j++){
    			if(ch[j][i]=='*'){
    				if(j==1||ch[j-1][i]!='*'){
    					c[j][i]=++cnt2;
    				}
    				else c[j][i]=cnt2;
    				a[h[j][i]][c[j][i]]=1;
    			}
    		}
    	}
    	for(int i=1;i<=cnt1;i++){//跑匈牙利 
    		memset(visit,0,sizeof visit);
    		ans+=dfs(i);
    	}
    	cout<<ans;
    	return 0;
    }
    
    

    本文章选自洛谷tj

    • 1

    信息

    ID
    1495
    时间
    1000ms
    内存
    256MiB
    难度
    9
    标签
    递交数
    10
    已通过
    5
    上传者