就是要求无向图最小路径覆盖问题,可以将每个点视为2个拆点i,i',从而分为两个顶点集,利用 最小路径覆盖数 = 顶点数 - 最大二分匹配数/2求得。 #include <iostream> #include <cstdio> #include <cstring> using namespace std; int city[41][11]; //第num个城市的坐标 bool map[401][401]; //第i个和第j个城市间可以连通 int num; //城市数 bool v[401]; int link[401]; // 匹配哪个V1中的点 int match; int row[4] = {0, 1, 0,-1}; int col[4] = {1, 0,-1, 0}; bool dfs(int x) { for (int y = 1; y <= num; ++y) if (map[x][y] && !v[y]) { v[y] = true; if (link[y] == 0 || dfs(link[y])) { link[y] = x; return true; } } return false; } void hungary() { for (int i = 1; i <= num; ++i) { memset(v, 0, sizeof(v)); if (dfs(i)) ++match; } } int main() { //freopen("temp.txt", "r", stdin); int test, h, w, x, y; char c; cin >> test; while (test--) { memset(city, 0, sizeof(city)); memset(map, 0, sizeof(map)); memset(link, 0, sizeof(link)); num = match = 0; cin >> h >> w; //行数,列数 for (int i = 1; i <= h; ++i) for (int j = 1; j <= w; ++j) { cin >> c; if (c == '*') city[i][j] = ++num; } for (int i = 1; i <= h; ++i) { for (int j = 1; j <= w; ++j) if (city[i][j]) for (int k = 0; k <= 3; ++k) { x = i + row[k]; y = j + col[k]; if (city[x][y]) map[ city[i][j] ][ city[x][y] ] = true; } } hungary(); cout << num-match/2<< endl; } return 0; }