都是求最大二分匹配的题目,只不过比模板题稍微灵活了一点,需要将题目进行一定的转化
pku2446
【题目大意】: r行c列的棋盘,现在要用1x2的骨牌来覆盖整个棋盘。骨牌不能重叠,且棋盘上有的方格不能放骨牌。问能不能将棋盘完全覆盖
【算法分析】:关键是建立二分的模型,用1x2的骨牌来覆盖棋盘其实隐含了一个性质,一张骨牌覆盖相邻的方格。就是说一次我们选择了两个方格,这两个方格相邻。把棋盘画成黑白棋盘,就转换成了二分图。每个方格可以和周围几个方格连线,寻找到最大的匹配数。比较最大匹配数*2是否和之前的空白方格数相等。另外可以发现一个剪枝,空白方格如果是奇数个,就肯定不能覆盖。
pku2446
#include<iostream>
using namespace std;
char g[40][40];
char mat[1155][1155];
int my[1155];
char vstd[1155];
int nx, ny;
int dir[4][2] = {{-1, 0},{0, 1},{1, 0},{0, -1}};
int nr, nc, nh;
int path(int s)
{
int e;
for(e = 1; e <= nr*nc; e++)
{
if(mat[s][e] && !vstd[e])
{
vstd[e] = 1;
if(my[e]==-1 || path(my[e]))
{
my[e] = s;
return 1;
}
}
}
return 0;
}
int MaxMatch()
{
int res = 0;
for(int i = 1; i <= nr*nc; i++)
{
memset(vstd, 0, sizeof(vstd));
res += path(i);
}
return res;
}
int main()
{
scanf("%d %d %d", &nr, &nc, &nh);
int i, j, k, ni, nj, x, y;
memset(g, 1, sizeof(g));
memset(mat, 0, sizeof(mat));
for(i = 1; i <= nh; i++)
{
scanf("%d %d", &y, &x);
g[x][y] = 0;
}
nx = 0;
ny = 0;
memset(my, -1, sizeof(my));
for(i = 1; i <= nr; i++)
{
for(j = 1; j <= nc; j++)
{
if((i+j)%2==1 && g[i][j]==1)ny++;
if((i+j)%2==0 && g[i][j]==1)
{
nx++;
for(k = 0; k < 4; k++)
{
ni = i+dir[k][0];
nj = j+dir[k][1];
if(g[ni][nj]==1 && ni>=1 && ni<=nr && nj>=1 && nj<=nc)
{
mat[(i-1)*nc+j][(ni-1)*nc+nj] = 1;
if(!my[(ni-1)*nc+nj])
my[(ni-1)*nc+nj]=(i-1)*nc+j;
}
}
}
}
}
if(nx!=ny)
puts("NO");
else
{
int res = MaxMatch();
if(res == nx)
puts("YES");
else
puts("NO");
}
return 0;
}
pku1719
【题目大意】:
一个r行c列的棋盘,每列中有2个白色方格和r-2个黑色方格,问你能否在每一列选出一个白色方格,共c个方格,使得这c个方格没有两个在同一行?如果能,输出方案。否则输出“NO”。
PS:刚才连题意都看不懂,太吭人了
【算法分析】:棋盘类的另一种二分方法是行列二分,即把行看做一方,列看做一方。这道题是要选出来的白格没有两个同行。可以算行列的二分匹配,求出来的最大匹配,如果等于c,说明选出来的格子都不在同行同列。如果有两个不同列的白格不得不在同行,那么算出来的最大匹配小于c。最后输出方案,就利用匈牙利算法保存的mx[]求出具体方格。
注意:最后在输出的时候要特别注意,题目要求输出的顺序,是按照连续的列输出的,而是在用匈牙利算法时,是为每一行找一个可匹配的列,所以并非所有列都有匹配,而对于还没有匹配的列,可以和任意满足条件的行匹配(其实,我也不知道为什么,求解释^-^)
pku1719
#include<iostream>
using namespace std;
char mat[1005][1005];
int nx, ny;
int match[1005];
char vstd[1005];
int path(int s)
{
int e;
for(e = 1; e <= ny; e++)
{
if(mat[s][e] && !vstd[e])
{
vstd[e] = 1;
if(match[e]==-1 || path(match[e]))
{
match[e] = s;
return 1;
}
}
}
return 0;
}
int MaxMatch()
{
int s, res = 0;
for(s = 1; s <= nx; s++)
{
memset(vstd, 0, sizeof(vstd));
res += path(s);
}
return res;
}
int main()
{
int cas;
int i, j;
int e1, e2;
scanf("%d", &cas);
while(cas--)
{
scanf("%d %d", &nx, &ny);
memset(mat, 0, sizeof(mat));
memset(match, -1, sizeof(match));
for(i = 1; i <= ny; i++)
{
scanf("%d %d", &e1, &e2);
mat[e1][i] = 1;
mat[e2][i] = 1;
}
if(ny < nx)
{
printf("NO\n");
continue;
}
int res = MaxMatch();
if(res == nx)
{
int k = 0;
for(i = 1; i <= ny; i++)
{
if(match[i]==-1)
{
for(j = 1; j <= nx; j++)
{
if(mat[j][i]==1)
{
if(k == 0)
{printf("%d", j);k++;}
else printf(" %d", j);
break;
}
}
}
else
{
if(k == 0){printf("%d", match[i]);k++;}
else printf(" %d", match[i]);
}
}
printf("\n");
}
else
printf("NO\n");
}
return 0;
}