题目大意:给定一地图,*可以和相邻的*匹配成一对儿,问最少需要对儿匹配才能使所有*都被匹配到。
很直白的最小点覆盖,即ans = 点集数-最大匹配数。
不过一开始要对图进行遍历得到点集,找到一个*就把点集数+1,并和周围的匹配即可。为了防止重复,
我只匹配了左边和上边的点。由于用邻接表保存了双向路,所以最后匹配结果会是最大匹配的二倍。
数据范围是40*10,匈牙利即可,因此不用Karp进行优化。
附AC代码:
#include <stdio.h> #include <algorithm> #include <string.h> using namespace std; #define oo 0x3f3f3f3f char maps[50][20]; int nums[50][20]; struct ad { int next, to; } edge[1000000]; int head[1100], edge_num, used[1100], vis[1100]; void Add(int x, int y) { edge[edge_num].next = head[x]; edge[edge_num].to = y; head[x] = edge_num++; } bool Hungary(int u) { for(int i=head[u]; i!=-1; i=edge[i].next) { int To = edge[i].to; if(!vis[To]) { vis[To] = 1; if(!used[To] || Hungary(used[To])) { used[To] = u; return true; } } } return false; } int main() { int T; scanf("%d", &T); while(T--) { int m, n; scanf("%d %d", &m, &n); for(int i=0; i<m; i++) scanf("%s", maps[i]); int cnt = 0; memset(head, -1, sizeof(head)); edge_num = 0; for(int i=0; i<m; i++) for(int j=0; j<n; j++) { if(maps[i][j]==‘*‘) { cnt++; nums[i][j] = cnt; if(i>=1 && maps[i-1][j]==‘*‘) { Add(nums[i-1][j], nums[i][j]); Add(nums[i][j], nums[i-1][j]); } if(j>=1 && maps[i][j-1]==‘*‘) { Add(nums[i][j], nums[i][j-1]); Add(nums[i][j-1], nums[i][j]); } } } memset(used, 0, sizeof(used)); int ans = 0; for(int i=1; i<=cnt; i++) { memset(vis, 0, sizeof(vis)); if(Hungary(i))ans++; } printf("%d\n", cnt-ans/2); } return 0; }
时间: 2024-10-14 09:54:56