4 461 11 42 24 14 24 44 344 23 22 23 10 0 Sample Output4(1,2)--(1,3)(2,1)--(3,1)(2,3)--(3,3)(2,4)--(3,4)3(1,1)--(2,1)(1,2)--(1,3)(2,3)--(3,3) 题目大意:给你一个n*m的矩阵,其中有些格子不能填东西,然后问你在空白处最多能填多少个1*2的方块
题目思路:
首先我们想到1*2的方块就是相邻两个格子的匹配,所以我们可以考虑将相邻格子建边,做最大匹配,最后的答案就是我们要求的,然后我们考虑如何构造二分图,应为这是个二维坐标,所以我们为了方便可以把二维坐标转换成一维坐标,然后枚举所有格子,分成奇偶,行列相加为偶数的和行列相加为奇数的连边,因为两个相邻格子的奇偶不同,然后进行最大匹配,集合的大小就是n*m,最后最大匹配的答案就是我们要求的,对于输出边,我们可以从link数组当中记录的连接边的情况来输出,我们枚举i,
如果link[i]不等于-1,这时候我们就知道i和link[i]之间有一条边
AC代码:
#include<cstring>#include<cstdio>#include<vector>using std::vector;const int maxn = 2e4+100;bool vis[maxn],mp[205][205];int link[maxn];int n,m,k;vector<int>edge[maxn];bool dfs(int u){ for(int i=0;i<edge[u].size();i++){ int v = edge[u][i]; if(!vis[v]){ vis[v]=true; if(link[v]==-1||dfs(link[v])){ link[v]=u; return true; } } } return false;}void graph(){ for(int i=1;i<=n*m;i++)edge[i].clear(); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int x = (i-1)*m+j; if(!mp[i][j]&&(i+j)%2){ if(j+1<=m&&!mp[i][j+1]){ //枚举偶数点的四个方向 edge[x].push_back(x+1); } if(i+1<=n&&!mp[i+1][j]){ edge[x].push_back(x+m); } if(j-1>=1&&!mp[i][j-1]){ edge[x].push_back(x-1); } if(i-1>=1&&!mp[i-1][j]){ edge[x].push_back(x-m); } } } }}int main(){ while(scanf("%d%d",&n,&m),n+m){ scanf("%d",&k); memset(link,-1,sizeof(link)); memset(mp,false,sizeof(mp)); for(int j=1;j<=k;j++) { int x,y;scanf("%d%d",&x,&y); mp[x][y]=true; } graph(); int ans = 0; for(int i=1;i<=n*m;i++){ memset(vis,false,sizeof(vis)); if(dfs(i))ans++; } printf("%d/n",ans); if(ans>0){ for(int i=1;i<=n*m;i++){ //枚举连接的边 int j = link[i]; if(link[i]!=-1){ int x = i,y = j; printf("(%d,%d)--(%d,%d)/n",(x-1)/m+1,(x-1)%m+1,(y-1)/m+1,(y-1)%m+1); } } } printf("/n"); } return 0;}
新闻热点
疑难解答