原题:http://poj.org/problem?id=3020
有四种天线,分别可以朝四个方向覆盖一个城镇(place of interest)(可以看成一个天线可以覆盖两个城镇),给出一张图,星号代表城镇,空格代表空地,问最少需要多少天线可以覆盖所有的城镇。
node标记点并且给城镇编号,edge标识出城镇与城镇的相邻关系,构建一个无向图。其中,点代表城镇,边代表连接的两个城镇中,只有一个需要安装天线
-> 点的数量=最多需要安装多少天线
-> 尽量用边连接不重复的点
-> 二分图的最大匹配(相关知识)
注意:构造的图为无向图,匹配数量应该减半!因为结果而node_num - maxMatch()/2;
#include <iostream> using namespace std; char map[41][11]; int h, w; int node[41][11]; bool edge[405][405]; int nn = 0; bool vis[405]; int match[405]; int path(int u) { for (int v = 1; v <= nn; ++v) { if (!vis[v] && edge[u][v]) { vis[v] = 1; if (match[v] == -1 || path(match[v])) { match[v] = u; return 1; } } } return 0; } int maxMatch() { int res = 0; memset(match, -1, sizeof(match)); for (int u = 1; u <= nn; ++u) { memset(vis, 0, sizeof(vis)); if (path(u)) res++; } return res; } int main() { int S; cin >> S; while (S--) { cin >> h >> w; nn = 0; memset(node, 0, sizeof(node)); memset(edge, 0, sizeof(edge)); for (int i = 1; i <= h; ++i) { for (int j = 1; j <= w; ++j) { cin >> map[i][j]; if (map[i][j] == '*') node[i][j] = ++nn; //记录点并且编号 } } int tmp; //构造邻接矩阵,表示城镇之间的相邻关系 for (int i = 1; i <= h; ++i) { for (int j = 1; j <= w; ++j) { tmp = node[i][j]; if (tmp > 0) { if (i > 1) { if (node[i - 1][j] > 0) edge[tmp][node[i - 1][j]] = 1; } if (i < h) { if (node[i + 1][j] > 0) edge[tmp][node[i + 1][j]] = 1; } if (j > 1) { if (node[i][j - 1] > 0) edge[tmp][node[i][j - 1]] = 1; } if (j < w) { if (node[i][j + 1] > 0) edge[tmp][node[i][j + 1]] = 1; } } } } //求最大匹配,参看上文二分图最大匹配的相关知识(连接) cout << nn - maxMatch()/2 << endl; } return 0; }
