标签:
题目链接:http://poj.org/problem?id=2446
给你一个n*m的棋盘,其中有k个洞,现在有1*2大小的纸片,纸片不能覆盖洞,并且每个格子最多只能被覆盖一次。问你除了洞口之外这个棋盘是否能被纸片填满。
这个题目一眼很难看出是二分图匹配...
可以根据i和j性质可以看出,i+j为奇数的上下相邻的i‘和j‘一定是偶数,那么一个1*2的纸片的i+j一定是一个奇数一个偶数。所以我是建立一个二分图两个集合,将i+j为奇数的点与上下左右相邻的点连在一起,当然点不是洞。最后就用匈牙利算法求最大匹配数,然后就简单了。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 using namespace std; 6 const int N = 35* 35; 7 vector <int> G[N]; 8 int match[N] , tx[] = {-1 , 0 , 1 , 0} , ty[] = {0 , 1 , 0 , -1} , n , m; 9 bool vis[N] , map[35][35]; 10 11 bool check(int x , int y) { 12 if(!map[x][y] && x >= 0 && y >= 0 && x < n && y < m) 13 return true; 14 return false; 15 } 16 17 bool dfs(int u) { 18 for(int i = 0 ; i < G[u].size() ; ++i) { 19 int v = G[u][i]; 20 if(!vis[v]) { 21 vis[v] = true; 22 if(match[v] == -1 || dfs(match[v])) { 23 match[v] = u; 24 return true; 25 } 26 } 27 } 28 return false; 29 } 30 31 int hungry() { 32 int res = 0; 33 for(int i = 0 ; i < n ; ++i) { 34 for(int j = 0 ; j < m ; ++j) { 35 if((i + j) % 2 && !map[i][j]) { 36 memset(vis , false , sizeof(vis)); 37 if(dfs(i*m + j)) { 38 res++; 39 } 40 } 41 } 42 } 43 return res; 44 } 45 46 int main() 47 { 48 int k , u , v; 49 while(cin >> n >> m >> k) { 50 memset(map , false , sizeof(map)); 51 memset(match , -1 , sizeof(match)); 52 for(int i = 0 ; i < n * m ; ++i) { 53 G[i].clear(); 54 } 55 for(int i = 0 ; i < k ; ++i) { 56 cin >> u >> v; 57 map[--v][--u] = true; 58 } 59 for(int i = 0 ; i < n ; ++i) { 60 for(int j = 0 ; j < m ; ++j) { 61 if(!map[i][j] && (i + j) % 2) { 62 for(int t = 0 ; t < 4 ; ++t) { 63 int x = i + tx[t] , y = j + ty[t]; 64 if(check(x , y)) { 65 G[i*m + j].push_back(x*m + y); 66 } 67 } 68 } 69 } 70 } 71 printf("%s\n" , 2*hungry() == n*m-k ? "YES" : "NO"); 72 } 73 return 0; 74 }
标签:
原文地址:http://www.cnblogs.com/Recoder/p/5664671.html