题意
- 在一个n*m的矩阵中,标记为’.’的为单独的一个点,标记为同一个数字的单元格和在一起是一个点,且是四联通的,为你这样建图之后它的最大独立集。
- n,m <= 10,数字数是0~9
思路
- 枚举0~9哪些放入独立集中,这样有2^10的复杂度
- 在上述的基础上,建立二分图,具体来说,是数字格的单元格不作为二分图的点加入,是放入独立集的数字格周围的单元格不算做二分图里的点。
- 剩余的点,i+j 是奇数的作为一个集合,i+j为偶数的是另一个集合
- 这里我用最大流解解决的最大独立集。
- 吐槽:真是各种T,各种剪枝。。。终于g++过了。。。c++还在T中。。。
实现
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstdio>
#include <vector>
#include <map>
using namespace std;
typedef pair<int,int> pii;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int MAXM = 500;
const int MAXN = 12;
const int maxn = 105;
const int INF = 0x3f3f3f3f;
struct Edge
{
int to,next,cap,flow;
}edge[MAXM];
int tol;
int head[maxn];
int gap[maxn],dep[maxn],pre[maxn],cur[maxn];
void init()
{
tol = 0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw = 0)
{
edge[tol].to = v;
edge[tol].cap = w;
edge[tol].next = head[u];
edge[tol].flow = 0;
head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = rw;
edge[tol].next = head[v];
edge[tol].flow = 0;
head[v] = tol++;
}
int sap(int start,int end,int N)
{
memset(gap,0,sizeof(gap));
memset(dep,0,sizeof(dep));
memcpy(cur,head,sizeof(head));
int u = start;
pre[u] = -1;
gap[0] = N;
int ans = 0;
while(dep[start] < N)
{
if(u == end)
{
int Min = INF;
for(int i = pre[u]; i != -1;i = pre[edge[i^1].to])
if(Min > edge[i].cap - edge[i].flow)
Min = edge[i].cap - edge[i].flow;
for(int i = pre[u];i != -1;i = pre[edge[i^1].to])
{
edge[i].flow += Min;
edge[i^1].flow -= Min;
}
u = start;
ans += Min;
continue;
}
bool flag = false;
int v;
for(int i = cur[u];i != -1;i = edge[i].next)
{
v = edge[i].to;
if(edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u])
{
flag = true;
cur[u] = pre[v] = i;
break;
}
}
if(flag)
{
u = v;
continue;
}
int Min = N;
for(int i = head[u];i != -1;i = edge[i].next)
if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)
{
Min = dep[edge[i].to];
cur[u] = i;
}
gap[dep[u]]--;
if(!gap[dep[u]])return ans;
dep[u] = Min+1;
gap[dep[u]]++;
if(u != start)u = edge[pre[u]^1].to;
}
return ans;
}
char diTu[MAXN][MAXN];
int mark[MAXN][MAXN];
int mark_now[MAXN][MAXN];
int id[MAXN][MAXN];
pii rid[maxn];
int g[maxn][maxn];
int vec[10];
pii d[4];
int num;
int id2[MAXN][MAXN];
int n_p;
int yingShe[10];
map<char,int> mapp;
bool judge(int s){
int ss = s;
for (int i=0;ss>0;i++,ss>>=1){
if ((ss&1) == 0){
continue;
}
for (int j=0;j<n_p;j++){
if (s & (1<<j)){
if (g[yingShe[i]][yingShe[j]]){
return false;
}
}
}
}
return true;
}
int main(){
int T;
d[0] = mp(0,1);
d[1] = mp(0,-1);
d[2] = mp(1,0);
d[3] = mp(-1,0);
cin>>T;
for (int t=1;t<=T;t++){
int n,m;
n_p = 0;
memset(mark,0,sizeof(mark));
memset(g,0,sizeof(g));
memset(vec,0,sizeof(vec));
num = 10;
mapp.clear();
mapp['.'] = 1;
scanf("%d%d",&n,&m);
for (int i=0;i<n;i++){
getchar();
for (int j=0;j<m;j++){
diTu[i][j] = getchar();
if (diTu[i][j] == '.'){
id[i][j] = num;
rid[num] = mp(i,j);
num++;
}
else{
vec[diTu[i][j] - '0']++;
id[i][j] = diTu[i][j] - '0';
mark[i][j] = 1;
}
}
}
for (int i=0;i<n;i++){
for (int j=0;j<m;j++){
if (mapp[diTu[i][j]] == 0){
yingShe[n_p] = diTu[i][j] - '0';
mapp[diTu[i][j]] = 1;
n_p ++;
}
}
}
for (int i=0;i<n;i++){
for (int j=0;j<m;j++){
int x = i;
int y = j;
for (int k=0;k<4;k++){
int x1 = x + d[k].fi;
int y1 = y + d[k].se;
if (x1 >= n || x1 < 0 || y1 >= m || y1 < 0){
continue;
}
g[id[x][y]][id[x1][y1]] = 1;
g[id[x1][y1]][id[x][y]] = 1;
}
}
}
for (int i=0;i<num;i++){
g[i][i] = 0;
}
int ans = 0;
for (int s=0;s<(1<<n_p);s++){
if (judge(s) == false)
continue;
int pren = 0;
int tmp = 0;
memcpy(mark_now,mark,sizeof(mark));
memset(id,0,sizeof(id));
init();
int ss = s;
for (int i=0;ss>0;i++,ss>>=1){
if ((ss&1) == 0 || vec[yingShe[i]] == 0){
continue;
}
pren++;
for (int j=10;j<num;j++){
if (g[yingShe[i]][j]){
int x = rid[j].fi;
int y = rid[j].se;
mark_now[x][y] = 1;
}
}
}
tmp = pren;
int sum = 0;
for (int i=0;i<n;i++){
for (int j=0;j<m;j++){
sum += (mark_now[i][j] ^ 1);
}
}
int now = 1;
for (int i=0;i<n;i++){
for (int j=0;j<m;j++){
if (mark_now[i][j] == 1){
continue;
}
if (i+j & 1){
if (id[i][j] != 0)
addedge(id[i][j],sum+1,1);
else{
addedge(now,sum+1,1);
id[i][j] = now;
now++;
}
}
else{
addedge(0,now,1);
id[i][j] = now;
now++;
int pre = now - 1;
for (int k=0;k<4;k++){
int x = i + d[k].fi;
int y = j + d[k].se;
if (x >= n || x < 0 || y >= m || y < 0){
continue;
}
if (mark_now[x][y] != 0){
continue;
}
if (id[x][y] != 0){
addedge(pre,id[x][y],1);
}
else{
addedge(pre,now,1);
id[x][y] = now;
now++;
}
}
}
}
}
tmp += sum - sap(0,sum+1,sum+2);
ans = max(ans,tmp);
}
printf("Case #%d: %d\n",t,ans);
}
return 0;
}