POJ 2446 Chessboard (二分匹配)
Chessboard
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 10743 | Accepted: 3338 |
Description
Alice and Bob often play games on chessboard. One day, Alice draws a board with size M * N. She wants Bob to use a lot of cards with size 1 * 2 to cover the board. However, she thinks it too easy to bob, so she makes some holes on the board (as shown in the figure below). We call a grid, which doesn’t contain a hole, a normal grid. Bob has to follow the rules below: 1. Any normal grid should be covered with exactly one card. 2. One card should cover exactly 2 normal adjacent grids.
Some examples are given in the figures below: A VALID solution. An invalid solution, because the hole of red color is covered with a card. An invalid solution, because there exists a grid, which is not covered. Your task is to help Bob to decide whether or not the chessboard can be covered according to the rules above.
Some examples are given in the figures below:
Input
There are 3 integers in the first line: m, n, k (0 < m, n <= 32, 0 <= K < m * n), the number of rows, column and holes. In the next k lines, there is a pair of integers (x, y) in each line, which represents a hole in the y-th row, the x-th column.
Output
If the board can be covered, output "YES". Otherwise, output "NO".
Sample Input
4 3 2 2 1 3 3
Sample Output
YES
Hint
A possible solution for the sample input.
Source
POJ Monthly,charlescpp
简单的而二分图的模板题。
建图方法好像不唯一。
我是把每个空格子当成一个点。
然后对于每个格子如果可以往上、下、左、右去找可以建立的边。
然后求最大匹配,如果最大匹配数刚好等于空格子数,输出YES,否则NO。
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> using namespace std; /* ************************************************************************** //二分图匹配(匈牙利算法的DFS实现) //初始化:g[][]两边顶点的划分情况 //建立g[i][j]表示i->j的有向边就可以了,是左边向右边的匹配 //g没有边相连则初始化为0 //uN是匹配左边的顶点数,vN是匹配右边的顶点数 //调用:res=hungary();输出最大匹配数 //优点:适用于稠密图,DFS找增广路,实现简洁易于理解 //时间复杂度:O(VE) //***************************************************************************/ //顶点编号从0开始的 const int MAXN=1610; int uN,vN;//u,v数目 int g[MAXN][MAXN]; int linker[MAXN]; bool used[MAXN]; bool dfs(int u)//从左边开始找增广路径 { int v; for(v=0;v<vN;v++)//这个顶点编号从0开始,若要从1开始需要修改 if(g[u][v]&&!used[v]) { used[v]=true; if(linker[v]==-1||dfs(linker[v])) {//找增广路,反向 linker[v]=u; return true; } } return false;//这个不要忘了,经常忘记这句 } int hungary() { int res=0; int u; memset(linker,-1,sizeof(linker)); for(u=0;u<uN;u++) { memset(used,0,sizeof(used)); if(dfs(u)) res++; } return res; } bool graph[50][50]; int num[50][50]; int main() { int n,m,k; int x,y; while(scanf("%d%d%d",&n,&m,&k)==3) { memset(g,0,sizeof(g)); memset(graph,false,sizeof(graph)); while(k--) { scanf("%d%d",&x,&y); x--; y--; graph[y][x]=true; } int tol=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++) { if(graph[i][j]==false) num[i][j]=tol++; } uN=vN=tol; for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(!graph[i][j]) { int u=num[i][j]; if(i>0 && !graph[i-1][j])g[u][num[i-1][j]]=1; if(j>0 && !graph[i][j-1])g[u][num[i][j-1]]=1; if(i<n-1 && !graph[i+1][j])g[u][num[i+1][j]]=1; if(j<m-1 && !graph[i][j+1])g[u][num[i][j+1]]=1; } if(hungary()==tol)printf("YES\n"); else printf("NO\n"); } return 0; }
人一我百!人十我万!永不放弃~~~怀着自信的心,去追逐梦想