思路:
如果将E确定状态了,当一个边的两边,一个是‘.’一个是‘D’的时候,答案就是+1。即一个边两边不同色,答案+1。这就和SPOJ839很像,然而,SPOJ839是求得不同色的最小,而不是最大。题目是想得到不同色边的最大,我们可以考虑同色边的最小。但是似乎直接建二分图是困难的,因为建立这个二分图有个要求,左右部分内部点连边,不能使得答案有变化。
为了解决这个问题(原来的图,使得同色的边最少),我们不放将方格按奇偶分为两部分,任意选一个部分,将其所有点取反。这样操作后,二分图就可以建立了。首先,二分图左右部分内部的点只有两种情况:1、相邻的,2、不相邻的。如果是情况1,说明他们原来是不同色的,并不能使得“同色的边的个数”变化,如果是不相邻的,那么本来就没有边,“同色的边”自然不会有变化。而二分图左右部分之间的两个点,如果有边,两个点自然是相邻的,又由于我们把原图的一部分取反了,其实连边的意思是这两个点原来同色的意思。
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<map>
#include<set>
using namespace std;
#define MP(x,y) make_pair((x),(y))
#define PB(x) push_back(x)
typedef __int64 LL;
//typedef unsigned __int64 ULL;
/* ****************** */
const int INF=100011122;
const double INFF=1e100;
const double eps=1e-8;
const int mod=1000000007;
const int NN=50;
const int MM=1000010;
/* ****************** */
struct G
{
int v,cap,next;
}E[NN*NN*4*2];
int p[NN*NN],T;
int tp[NN*NN],num[NN*NN],dis[NN*NN];
int preb[NN*NN],pred[NN*NN];
int qw[NN*NN];
int mat[NN][NN];
char ss[NN];
void add(int u,int v,int cap)
{
E[T].v=v;
E[T].cap=cap;
E[T].next=p[u];
p[u]=T++;
E[T].v=u;
E[T].cap=0;
E[T].next=p[v];
p[v]=T++;
}
int ISAP(int st,int en,int n)
{
int real_n=n+1;
int i,u;
int temp,id,f=0;
bool ok;
//预处理方法1
// for(i=0;i<=real_n;i++)
// {
// dis[i]=0;
// num[i]=0;
// }
// num[0]=real_n;
//预处理方法2,需要新加入队列数组qw[]
int head,tail;
for(i=0;i<=real_n;i++)
{
dis[i]=real_n;
num[i]=0;
}
head=tail=0;
qw[head=tail=0]=en;
dis[en]=0;
num[0]++;
while(head<=tail)
{
u=qw[head++];
for(i=p[u];i+1;i=E[i].next)
{
if(E[i^1].cap>0 && dis[E[i].v]==real_n)
{
num[ dis[u]+1 ]++;
dis[E[i].v]=dis[u]+1;
qw[++tail]=E[i].v;
}
}
}
for(i=0;i<=n;i++)
tp[i]=p[i];
u=st;
while(dis[st]<real_n)
{
if(u==en)
{
temp=INF;
while(u!=st)
{
temp=min(temp,E[ preb[u] ].cap);
u=pred[u];
}
u=en;
while(u!=st)
{
id=preb[u];
E[id].cap-=temp;
E[id^1].cap+=temp;
u=pred[u];
}
f+=temp;
}
ok=false;
for(; tp[u]+1 ;tp[u]=E[ tp[u] ].next)
{
G &e=E[tp[u]];
if(e.cap>0 && dis[u]==dis[e.v]+1)
{
ok=true;
pred[e.v]=u;
preb[e.v]=tp[u];
u=e.v;
break;
}
}
if(!ok)
{
temp=real_n-1; // real point -1
for(i=p[u];i+1;i=E[i].next)
{
if(E[i].cap>0)
temp=min(temp,dis[ E[i].v ]);
}
if(--num[ dis[u] ]==0)break;
num[ dis[u]=temp+1 ]++;
tp[u]=p[u];
if(u!=st)u=pred[u];
}
}
return f;
}
int main()
{
int cas,ee=0;
int n,m,i,j;
int st,en,id,ans;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&n,&m);
memset(mat,0,sizeof(mat));
memset(p,-1,sizeof(p));
T=0;
for(i=1;i<=n;i++)
{
scanf("%s",ss+1);
for(j=1;j<=m;j++)
{
if(ss[j]=='D')
mat[i][j]=0;
else if(ss[j]=='.')
mat[i][j]=1;
else
mat[i][j]=-1;
}
}
for(i=0;i<=n+1;i++)
for(j=0;j<=m+1;j++)
{
if((i+j)&1)
{
if(mat[i][j]==0)
mat[i][j]=1;
else if(mat[i][j]==1)
mat[i][j]=0;
}
}
st=(n+2)*(m+2);
en=st+1;
for(i=0;i<=n+1;i++)
for(j=0;j<=m+1;j++)
{
id=i*(m+2)+j;
if(mat[i][j]==0)
{
add(st,id,INF);
if(i<=n && mat[i+1][j]!=0)
add(id,(i+1)*(m+2)+j,1);
if(j<=m && mat[i][j+1]!=0)
add(id,i*(m+2)+j+1,1);
}
else if(mat[i][j]==1)
{
add(id,en,INF);
if(i<=n && mat[i+1][j]!=1)
add((i+1)*(m+2)+j,id,1);
if(j<=m && mat[i][j+1]!=1)
add(i*(m+2)+j+1,id,1);
}
else
{
if(i<=n)
{
if(mat[i+1][j]==0)
add((i+1)*(m+2)+j,id,1);
else if(mat[i+1][j]==1)
add(id,(i+1)*(m+2)+j,1);
else
{
add((i+1)*(m+2)+j,id,1);
add(id,(i+1)*(m+2)+j,1);
}
}
if(j<=m)
{
if(mat[i][j+1]==0)
add(i*(m+2)+j+1,id,1);
else if(mat[i][j+1]==1)
add(id,i*(m+2)+j+1,1);
else
{
add(i*(m+2)+j+1,id,1);
add(id,i*(m+2)+j+1,1);
}
}
}
}
ans=(m+2)*(n+1) + (n+2)*(m+1) - ISAP(st,en,en);
printf("Case %d: ",++ee);
printf("%d\n",ans);
}
return 0;
}