POJ 2226 Muddy Fields (最小点覆盖集,对比POJ 3041)
题意
给出的是N*M的矩阵,同样是有障碍的格子,要求每次只能消除一行或一列中连续的格子,最少消除多少次可以全部清除。思路
相当于POJ 3041升级版,不同之处在于这次不能一列一行全部消掉,那些非障碍的格子不能消。 但是我们还是要抓住关键点:每个格子必须消除,要么以行消,要么以列消。并且我们发现如果以行消得话,一定是以这连续障碍行的最左端为起点,同理列是以最上端为起点。那么我们就又把消除方式变成两种了。这时就可以把障碍当作边,两种覆盖方式分别作为两断点,求二分图最小点覆盖集。 行列方式的起点共有R*C种,即二分图两个点集均需要R*C个点。并且注意这题R\C好像不止50= =……我的二分图点大小开到2000才从RE变成AC……代码
using namespace std; const int MAXV = 2005; //N1+N2 vectoradj[MAXV]; struct MaximumMatchingOfBipartiteGraph{ int vn; void init(int n){ //二分图两点集点的个数 vn = n; for (int i = 0; i <= vn; i ++) adj[i].clear(); } void add_uedge(int u, int v){ adj[u].push_back(v); adj[v].push_back(u); } bool vis[MAXV]; int mat[MAXV]; //记录已匹配点的对应点 bool cross_path(int u){ for (int i = 0; i < (int)adj[u].size(); i ++){ int v = adj[u][i]; if (!vis[v]){ vis[v] = true; if (mat[v] == 0 || cross_path(mat[v])){ mat[v] = u; mat[u] = v; return true; } } } return false; } int hungary(){ mem(mat, 0); int match_num = 0; for (int i = 1; i <= vn; i ++){ mem(vis, 0); if (!mat[i] && cross_path(i)){ match_num ++; } } return match_num; } void print_edge(){ for (int i = 1; i <= vn; i ++){ for (int j = 0; j < (int)adj[i].size(); j ++){ printf("u = %d v = %d\n", i, adj[i][j]); } } } }match; char map[MAXV][MAXV]; int main(){ //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); int r, c; scanf("%d %d", &r, &c); getchar(); match.init(r*c*2); for (int i = 0; i < r; i ++){ for (int j = 0; j < c; j ++){ scanf("%c", &map[i][j]); if (map[i][j] == '*'){ int k = j - 1, l = i -1; while(k >= 0 && map[i][k] == '*'){ k --; } k ++; while(l >= 0 && map[l][j] == '*'){ l --; } l ++; match.add_uedge(i*c+k+1, r*c+l*c+j+1); } } getchar(); } //match.print_edge(); printf("%d\n", match.hungary()); return 0; }
举杯独醉,饮罢飞雪,茫然又一年岁。 ------AbandonZHANG