[HDU-5556] Land of Farms (2015 ICPC Hefei E)

含有数字的块最多只有10个,暴力枚举这些块的状态,剩下的非数字单元用二分图匹配来求数量。下面拿全是 '.' 的情况来说怎么个二分图匹配求解。首先一个单位能相邻的只有周围的4个点,那么将 x 坐标+ y 坐标的奇偶性作为分组条件就可以分成一个二分图,想象一下这么分组的话就是一个黑白交叉的棋盘似的。然后相邻的格子肯定就连边,然后跑二分图匹配求最大匹配数。用总的单元格数减去这个最大匹配数,得到的就是需要求的最大独立集大小。思想就是取全部然后去掉一些点使得没有两个点相邻。(注意数字块相邻的哪些单元格不要考虑在内,就是既不算入单元格总数也不算入二分图匹配中。)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <list>
#include <algorithm>
#include <cmath>
#include <sstream>
#include <iomanip>
#define endl '\n'
#define fin freopen("in.txt", "r", stdin)
#define fout freopen("out.txt", "w", stdout)
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
typedef pair<LL, int> pli;
typedef pair<int, double> pid;
typedef pair<double, int> pdi;
const int INF = 0x3f3f3f3f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
inline int read(){
    register int x; register char c(getchar()); register bool k;
    while((c < '0' || c > '9') && c ^ '-') if((c = getchar()) == EOF) exit(0);
    if(c ^ '-') x = c & 15, k = 1; else x = 0, k = 0;
    while(c = getchar(), c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15);
    return k ? x : -x;
}
void write(register int a){
    if(a < 0) putchar('-'), a = -a;
    if(a <= 9) putchar(a | '0');
    else write(a / 10), putchar((a % 10) | '0');
}

const int dr[] = {0, 1, 0, -1};
const int dc[] = {1, 0, -1, 0};
int N, M;
char table[15][15];
int anthor_name[15];
int anci_cnt; 
int res;
vector<int> tmp_v;
set<pii> tmp_s;
bool flag[15][15];

bool val(int r, int c){
    return r >= 1 && r <= N && c >= 1 && c <= M;
}

bool connect(){
    for(int i = 0; i < tmp_v.size(); i++){
        for(int j = i + 1; j < tmp_v.size(); j++){
            int x = min(tmp_v[i], tmp_v[j]), y = max(tmp_v[i], tmp_v[j]);
            if(tmp_s.count(pii(x, y))) return true;
        }
    }
    return false;
}

const int MAX_V = 100 + 5; 
// 复杂度为|V|*|E|
vector<int> G[MAX_V];  // 图的邻接表表示
int match[MAX_V];      // 所匹配的顶点
bool used[MAX_V];      // DFS中用到的访问标记

void add_edge(int u, int v){
    G[u].push_back(v);
    G[v].push_back(u);
}

bool dfs(int v){
    used[v] = true;
    for(int i = 0; i < G[v].size(); i++){
        int u = G[v][i], w = match[u];
        if(w < 0 || !used[w] && dfs(w)){
            match[v] = u;
            match[u] = v;
            return true;
        }
    }
    return false;
}

// 求[0, V - 1]顶点编号的二分图的最大匹配
int bipartite_matching(int V){
    int res = 0;
    memset(match, -1, V * sizeof(int));
    for(int v = 0; v < V; v++){
        if(match[v] < 0){
            memset(used, 0, V * sizeof(bool));
            if(dfs(v)) res++;
        }
    }
    return res;
}

int main(){
    int t = read();
    for(int tt = 1; tt <= t; tt++){
        N = read(), M = read();
        anci_cnt = 0;
        res = 0;
        for(int i = 0; i < 15; i++) anthor_name[i] = -1;
        for(int i = 1; i <= N; i++){
            for(int j = 1; j <= M; j++){
                char ch = getchar();
                if(ch != '.'){
                    if(anthor_name[ch - '0'] == -1){
                        anthor_name[ch - '0'] = anci_cnt++;
                        ch = '0' + anci_cnt - 1;
                    }else{
                        ch = '0' + anthor_name[ch - '0'];
                    }
                }
                table[i][j] = ch;
            }
            getchar();
        }
        /*for(int i = 1; i <= N; i++){
            for(int j = 1; j <= M; j++){
                cout << table[i][j];
            }
            cout << endl;
        }*/

        // 相邻预处理
        tmp_s.clear();
        for(int i = 1; i <= N; i++){
            for(int j = 1; j <= M; j++){
                if(table[i][j] == '.') continue;
                int tmp1 = table[i][j] - '0', tmp2;
                for(int k = 0; k < 4; k++){
                    int ti = i + dr[k], tj = j + dc[k];
                    if(val(ti, tj)){
                        if(table[ti][tj] != '.'){
                            tmp2 = table[ti][tj] - '0';
                            if(tmp1 != tmp2)
                                tmp_s.insert(pii(min(tmp1, tmp2), max(tmp1, tmp2)));
                        }
                    }
                }
            }
        }
        /*for(auto it:tmp_s){
            cout << it.first << ' ' << it.second << endl;
        }*/

        //枚举
        int enum_num = 1 << anci_cnt;
        for(int i = 0; i < enum_num; i++){
            tmp_v.clear();
            memset(flag, 0, sizeof(flag));
            int tot = 0;
            for(int j = 0; j < anci_cnt; j++){
                //cout << 1 << endl;
                if(i >> j & 1){
                    tmp_v.push_back(j);
                    tot++;
                }
            }
            
            if(connect()) continue;
            //cout << tot << endl;
            for(int i = 0; i < tmp_v.size(); i++){
                for(int r = 1; r <= N; r++){
                    for(int c = 1; c <= M; c++){
                        if(table[r][c] == '0' + tmp_v[i]){
                            for(int k = 0; k < 4; k++){
                                int tr = r + dr[k], tc = c + dc[k];
                                if(val(tr, tc)) flag[tr][tc] = 1;
                            }
                        }
                    }
                }
            }
            for(int r = 1; r <= N; r++){
                for(int c = 1; c <= M; c++){
                    if(table[r][c] != '.') flag[r][c] = 1;
                }
            }
            /*cout << endl;
            for(int i = 1; i <= N; i++){
                for(int j = 1; j <= M; j++){
                    cout<< flag[i][j];
                }
                cout << endl;
            }*/
            for(int i = 0; i < MAX_V; i++) G[i].clear();
            for(int r = 1; r <= N; r++){
                for(int c = 1; c <= M; c++){
                    if(flag[r][c] == 1) continue;
                    tot++;
                    if((r + c) % 2) continue;
                    for(int k = 0; k < 4; k++){
                        int tr = r + dr[k], tc = c + dc[k];
                        if(val(tr, tc) && flag[tr][tc] == 0){
                            add_edge((tr - 1) * M + tc - 1, (r - 1) * M + c - 1);
                        }
                    }
                }
            }
            int tmp = bipartite_matching(N * M);
            //cout << tmp << endl;
            tot -= tmp;
            res = max(res, tot);
        }
        printf ("Case #%d: %d\n", tt, res);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ACHappy-yjy/p/13170049.html