1 /* 2 题意:*的点占据后能顺带占据四个方向的一个*,问最少要占据多少个 3 匈牙利算法:按坐标奇偶性把*分为两个集合,那么除了匹配的其中一方是顺带占据外,其他都要占据 4 */ 5 #include <cstdio> 6 #include <algorithm> 7 #include <cstring> 8 #include <vector> 9 using namespace std; 10 11 const int MAXN = 4e2 + 10; 12 const int INF = 0x3f3f3f3f; 13 char s[44][11]; 14 int ha[44][11]; 15 bool vis[MAXN]; 16 int lk[MAXN]; 17 vector<int> G[MAXN]; 18 int dx[4] = {-1, 1, 0, 0}; 19 int dy[4] = {0, 0, -1, 1}; 20 int un, vn; 21 22 bool DFS(int u) 23 { 24 for (int i=0; i<G[u].size (); ++i) 25 { 26 int v = G[u][i]; 27 if (!vis[v]) 28 { 29 vis[v] = true; 30 if (lk[v] == -1 || DFS (lk[v])) 31 { 32 lk[v] = u; return true; 33 } 34 } 35 } 36 37 return false; 38 } 39 40 int hungary(void) 41 { 42 int res = 0; memset (lk, -1, sizeof (lk)); 43 for (int i=1; i<=un; ++i) 44 { 45 memset (vis, false, sizeof (vis)); 46 if (DFS (i)) res++; 47 } 48 49 return res; 50 } 51 52 int main(void) //POJ 3020 Antenna Placement 53 { 54 //freopen ("POJ_3020.in", "r", stdin); 55 56 int t; scanf ("%d", &t); 57 while (t--) 58 { 59 int h, w; scanf ("%d%d", &h, &w); 60 for (int i=1; i<=h; ++i) 61 { 62 scanf ("%s", s[i] + 1); 63 } 64 65 un = vn = 0; 66 for (int i=1; i<=h; ++i) 67 { 68 for (int j=1; j<=w; ++j) 69 { 70 if (s[i][j] == ‘*‘) 71 { 72 if ((i+j) & 1) ha[i][j] = ++un; 73 else ha[i][j] = ++vn; 74 } 75 } 76 } 77 78 for (int i=1; i<=un; ++i) G[i].clear (); 79 80 for (int i=1; i<=h; ++i) 81 { 82 for (int j=1; j<=w; ++j) 83 { 84 if (s[i][j] == ‘*‘ && (i+j) & 1) 85 { 86 for (int k=0; k<4; ++k) 87 { 88 int tx = i + dx[k]; int ty = j + dy[k]; 89 if (tx >= 1 && tx <= h && ty >= 1 && ty <= w && s[tx][ty] == ‘*‘) 90 G[ha[i][j]].push_back (ha[tx][ty]); 91 } 92 } 93 } 94 } 95 96 printf ("%d\n", un + vn - hungary ()); 97 } 98 99 return 0; 100 }
时间: 2024-08-01 19:29:27