題意
給一個的網格,其中有“*”和“.”和“+”,每次可以選擇覆蓋一個"+“或“*”和與它相鄰的兩個”.",如果選的是“*”則兩個“.”必須相對。每個點只能被覆蓋一次,問最多能覆蓋多少次。
分析
把每個“+”和“*”拆成兩個點並連邊,“+”的每個點對四周的“.”連邊,“*”則一個點向上下方向連邊,另一個點向左右方向連邊,可以發現最大圖匹配減去“+”和“*”的數量即爲答案。
代碼
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=20005;
const int L=105;
int n,m,cnt,last[N],ty[N],tic[N],tim,f[N],match[N],pre[N];
int tot,dx[4]={0,1,0,-1},dy[4]={1,0,-1,0},id1[L][L],id2[L][L],sz;
bool used[26];
struct edge{int to,next;}e[N*10];
queue<int> que;
char str[L][L];
void addedge(int u,int v)
{
e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}
int find(int x)
{
if (f[x]==x) return x;
else return f[x]=find(f[x]);
}
int lca(int x,int y)
{
for (tim++;;swap(x,y))
if (x)
{
x=find(x);
if (tic[x]==tim) return x;
tic[x]=tim;x=pre[match[x]];
}
}
void shrink(int x,int y,int p)
{
while (find(x)!=p)
{
pre[x]=y;y=match[x];
if (ty[y]==2) ty[y]=1,que.push(y);
if (find(x)==x) f[x]=p;
if (find(y)==y) f[y]=p;
x=pre[y];
}
}
bool aug(int s)
{
for (int i=1;i<=sz;i++) f[i]=i,ty[i]=pre[i]=0;
while (!que.empty()) que.pop();
que.push(s);ty[s]=1;
while (!que.empty())
{
int x=que.front();que.pop();
for (int i=last[x],y=e[i].to;i;i=e[i].next,y=e[i].to)
{
if (find(x)==find(y)||ty[y]==2) continue;
if (!ty[y])
{
ty[y]=2;pre[y]=x;
if (!match[y])
{
for (int tmp;y;y=tmp,x=pre[y])
tmp=match[x],match[x]=y,match[y]=x;
return 1;
}
else ty[match[y]]=1,que.push(match[y]);
}
else if (ty[y]==1)
{
int p=lca(x,y);
shrink(x,y,p);
shrink(y,x,p);
}
}
}
return 0;
}
void build()
{
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (str[i][j]=='.') id1[i][j]=++sz;
else id1[i][j]=++sz,id2[i][j]=++sz,addedge(id1[i][j],id2[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (str[i][j]=='*')
{
if (str[i][j-1]=='.') addedge(id1[i][j],id1[i][j-1]);
if (str[i][j+1]=='.') addedge(id1[i][j],id1[i][j+1]);
if (str[i-1][j]=='.') addedge(id2[i][j],id1[i-1][j]);
if (str[i+1][j]=='.') addedge(id2[i][j],id1[i+1][j]);
}
else if (str[i][j]=='+')
{
for (int k=0;k<4;k++)
{
int x=i+dx[k],y=j+dy[k];
if (str[x][y]=='.') addedge(id1[i][j],id1[x][y]),addedge(id2[i][j],id1[x][y]);
}
}
}
void block(int x,int y)
{
for (int k=0;k<4;k++)
{
int p=x+dx[k],q=y+dy[k];
if (str[p][q]>='a'&&str[p][q]<='z') used[str[p][q]-'a']=1;
}
}
char filter(int x,int y)
{
memset(used,0,sizeof(used));
block(x,y);
for (int k=0;k<4;k++)
{
int p=x+dx[k],q=y+dy[k];
if (id1[p][q]==match[id1[x][y]]||id1[p][q]==match[id2[x][y]]) block(p,q);
}
for (int i=0;i<26;i++)
if (!used[i]) return i+'a';
}
void output()
{
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (str[i][j]=='*'||str[i][j]=='+')
{
if (match[id1[i][j]]==id2[i][j]||!match[id1[i][j]]||!match[id2[i][j]]) continue;
char c=filter(i,j);
str[i][j]=c;
for (int k=0;k<4;k++)
{
int x=i+dx[k],y=j+dy[k];
if (match[id1[x][y]]==id1[i][j]||match[id1[x][y]]==id2[i][j]) str[x][y]=c;
}
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
printf("%c",str[i][j]);
puts("");
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%s",str[i]+1);
build();
int ans=0;
for (int i=1;i<=sz;i++) if (!match[i]&&aug(i)) ans++;
output();
return 0;
}