hdu1045

题目链接

左边白方格里放小球,满足同一行、列只有一个(被黑块隔开)。问最多放多少个球。

------------------------------------------------------------------------------------------------------------

从贪心类别看到这个题的,读完题后只能想到枚举的解法 ==。智商有限。

看了题解后才知道怎么贪心,还有一个最大二分匹配的解法。

1.枚举

依次判断每个格子能不能放小球,如果能则返回 max{dfs(放),dfs(不放)},否则返回dfs(不放).

#define _CRT_SECURE_NO_DEPRECATE
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>

#define MAX(a,b) ((a)>=(b)?(a):(b))
#define MIN(a,b) ((a)<=(b)?(a):(b))
#define OO 0x0fffffff
typedef long long LL;
using namespace std;
typedef pair<int, int> int2;
const int dir[4][2] = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } };
char status[8][8];
int2 dots[16];
int dotcnt;
int n;

int dfs(int depth){
    if (depth == dotcnt){
        int ret = 0;
        for (int i = 0; i<n; i++) for (int j = 0; j<n; j++) if (status[i][j] == '*') ret++;
        return ret;
    }
    int x = dots[depth].first;
    int y = dots[depth].second;
    bool flag = true;

    for (int i = 0; i<4; i++){
        for (int j = 1; flag; j++){
            int tx = x + dir[i][0] * j;
            int ty = y + dir[i][1] * j;
            if (tx<0 || ty<0 || tx >= n || ty >= n) break;
            if (status[tx][ty] == 'X') break;
            if (status[tx][ty] == '*') { flag = false; break; }
        }
    }
    int no = dfs(depth + 1);
    if (flag) {
        status[x][y] = '*';
        int yes = dfs(depth + 1);
        status[x][y] = '.';
        return max(no,yes);
    }
    else return no;
}

int main(){
    while (scanf("%d", &n), n){
        dotcnt = 0;
        for (int i = 0; i<n; i++) {
            scanf("%s", status[i]);
            for (int j = 0; j<n; j++)
                 if (status[i][j] != 'X') dots[dotcnt++] = make_pair(i, j);
        }
        printf("%d
", dfs(0));
    }
    return 0;
}

2. 贪心

统计每个白块所在行和列的连通区域的面积s,从第一排开始处理,找到s最小的块,标记,继续找第一排中最小的,如果没有了则挪到下一排。

3. 二分匹配

现在还没复习到二分图,只写一下二分图的构造:

a. 列收缩。所有列中每一个联通的白块看做一个点。记该序列为A;

b. 行收缩。得到序列B;

c. 连边。对所有(a,b)属于(A,B),如果ab相交则连一条边

接下来就是最大二分匹配了

原文地址:https://www.cnblogs.com/redips-l/p/7243507.html