题目大意:
分析:
首先,由于古老的东西数目比较少,可以枚举选择了哪些古老的东西,然后删除古老的东西和选择的古老的东西四周的点,对于剩下的点跑匈牙利匹配。
ans=选择的古老的种类+剩下的点-二分图匹配/2
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <set>
using namespace std;
int n,m;
const int maxn = 10 + 10;
char s[maxn][maxn];
int tot ;
int vis[maxn];
bool choose[maxn];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
vector<int>G[100+5];
bool used[110];
int link[110];
bool can[maxn][maxn];
int ans;
int num1;
bool is_ok(int x,int y)
{
if(x>=0&&x<n&&y>=0&&y<m) return true;
return false;
}
bool judge()
{
// for(int i=1;i<=tot;i++) printf("%d ",choose[i]);
// printf("\n");
// cout<<vis[0]<<" "<<vis[2]<<endl;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(s[i][j]!='.'&&choose[vis[s[i][j]-'0']])
{
for(int k=0;k<4;k++)
{
int x=i+dx[k];
int y=j+dy[k];
if(is_ok(x,y)&&s[x][y]!='.'&&s[x][y]!=s[i][j]&&choose[vis[s[x][y]-'0']]==1)
{
// cout<<s[i][j]<<"..."<<s[x][y]<<" "<<choose[vis[s[i][j]-'0']]<<" "<<choose[vis[s[x][y]-'0']]<<endl;
return false;
}
}
}
}
}
return true;
}
int find_(int x)
{
for(int i=0;i<G[x].size();i++)
{
int j=G[x][i];
if(used[j]==false)
{
used[j]=true;
if(link[j]==0||find_(link[j]))
{
link[j]=x;
return true;
}
}
}
return false;
}
void solve()
{
// for(int i=1;i<tot;i++) if(choose[i]) printf("%d ",i);
// printf("\n");
//
if(!judge()) return ;
// for(int i=1;i<=tot;i++) printf("%d ",choose[i]);
// printf("\n");
// printf("success\n");
memset(can,0,sizeof(can));
for(int i=0;i<=n*m;i++) G[i].clear();
memset(link,0,sizeof(link));
int cnt=0,cnt1=0;
for(int i=1;i<=tot;i++)
{
if(choose[i]) cnt++;
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(s[i][j]!='.'&&choose[vis[s[i][j]-'0']])
{
for(int k=0;k<4;k++)
{
int x=i+dx[k];
int y=j+dy[k];
if(is_ok(x,y)&&s[x][y]=='.')
{
can[x][y]=1;
}
}
}
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(s[i][j]=='.'&&can[i][j]==0)
{
cnt1++;
for(int k=0;k<4;k++)
{
int x=i+dx[k];
int y=j+dy[k];
if(is_ok(x,y)&&s[x][y]=='.'&&can[x][y]==0)
{
//cout<<i<<" "<<j<<" "<<x<<" ****"<<y<<endl;
G[i*m+j].push_back(x*m+y);
}
}
}
}
}
int num = 0;
for(int i=0;i<n*m;i++)
{
memset(used,0,sizeof(used));
if(find_(i))
{
num++;
}
}
// cout<<num<<"..."<<cnt<<" "<<num1<<" "<<cnt1<<endl;
ans = max(ans,cnt1-num/2+cnt);
}
void dfs(int u)
{
if(u==tot+1)
{
solve();
return ;
}
choose[u]=1;
dfs(u+1);
choose[u]=0;
dfs(u+1);
}
int main()
{
int T;
scanf("%d",&T);
int kase=0;
while(T--)
{
memset(vis,0,sizeof(vis));
memset(choose,0,sizeof(choose));
ans=0;
tot=0;
num1=0;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%s",s[i]);
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(s[i][j]!='.')
{
num1++;
if(!vis[s[i][j]-'0'])
{
//++tot;
vis[s[i][j]-'0'] = ++tot;
//cout<<s[i][j]<<" "<<tot<<endl;
}
}
}
}
dfs(1);
printf("Case #%d: %d\n",++kase,ans);
}
return 0;
}