给定一个地图,范围10*10,每个位置上有一个数字,你可以执行小于等于k次操作,每次操作为在地图中选取一个点,然后可以从这个点往右或者下跳若干次,每次跳跃的花费为两个点之间的距离减一,若两个点上的数字相同,则可以得到与这个数字相同的分数。问经过小于等于k次操作之后,访问每个点有且只有一次的前提下,能够得到的最高分数是多少?
把每个点拆成入点和出点,每个点的入点到出点有一条流量为1,费用为-MAX的边,这样保证每个点都走且只走一次。每个点的出点到其他点的入点连边,流量为1,费用为这次跳跃所能得到的分数的相反数。每个点的出点向汇连边,源向每个点的入点连边,流量为1,费用为0。超级源向源流流量为k,费用为0的边。
这样,从超级源向汇的最小费用最大流的大小的相反数,就是恰好执行k次操作时,所能的到的最大分数。
枚举执行的操作数,每次在残量网络上将超级源向源的边的可流流量增1,这样每次求最大流其实只是一次SPFA。
若k<min(n,m),则无法流通。
#include <cstdio>
#include <cstring>
const int MAXINT=(1<<30);
struct MinCostFlow {
static const int MAXNODE=1000;
static const int MAXEDGE=3000;
struct Node {
int fe,c,f,fromNode,curCost,fromEdge;
bool inque;
};
struct Edge {
int f,t,ne,c;
};
Node a[MAXNODE];
Edge b[MAXEDGE*2];
int d[MAXNODE];
int s,t,n,p,cost;
void clear(int nn,int ss,int tt) {
n=nn;s=ss;t=tt;
for (int i=0;i<=n;i++) {
a[i].fe=-1;
a[i].f=0;
a[i].c=0;
}
p=0;
cost=0;
}
int putedge(int x,int y,int f,int c) {
//printf("%d %d %d %d\n",x,y,f,c);
b[p].ne=a[x].fe;
b[p].t=y;
b[p].f=f;
b[p].c=c;
a[x].fe=p;
p++;
b[p].ne=a[y].fe;
b[p].t=x;
b[p].f=0;
b[p].c=-c;
a[y].fe=p;
p++;
return p-2;
}
bool spfa() {
int i,p,q,j;
for (i=0;i<=n;i++) {
a[i].curCost=MAXINT;
a[i].fromNode=-1;
a[i].fromEdge=-1;
a[i].inque=false;
}
p=q=0;
d[q++]=s;
a[s].inque=true;
a[s].curCost=0;
while (p!=q) {
i=d[p];
for (j=a[i].fe;j!=-1;j=b[j].ne) {
if (b[j].f>0&&b[j].c+a[i].curCost<a[b[j].t].curCost) {
a[b[j].t].curCost=a[i].curCost+b[j].c;
a[b[j].t].fromNode=i;
a[b[j].t].fromEdge=j;
if (a[b[j].t].inque==false) {
a[b[j].t].inque=true;
d[q]=b[j].t;
q=(q+1)%MAXNODE;
}
}
}
a[i].inque=false;
p=(p+1)%MAXNODE;
}
if (a[t].curCost==MAXINT) return false;
p=MAXINT;
q=0;
for (i=t;i!=s;i=a[i].fromNode) {
d[q++]=i;
if (p>b[a[i].fromEdge].f) p=b[a[i].fromEdge].f;
}
j=0;
for (i=q-1;i>=0;i--) {
j+=b[a[d[i]].fromEdge].c*p;
b[a[d[i]].fromEdge].f-=p;
b[a[d[i]].fromEdge^1].f+=p;
a[d[i]].c+=j;
a[d[i]].f+=p;
}
return true;
}
void flow() {
int i;
a[s].f=MAXINT;
while (spfa()) ;
}
int getFlow() {
return a[t].f;
}
int getCost() {
return a[t].c;
}
};
MinCostFlow c;
int n,m,kk,nm;
int a[10][10];
int ans;
int tran(int i,int j) {
return i*m+j+1;
}
int main() {
int i,j,k,t,tt,curk;
scanf("%d",&tt);
for (t=1;t<=tt;t++) {
scanf("%d%d%d",&n,&m,&kk);
for (i=0;i<n;i++) {
for (j=0;j<m;j++) {
char c;
scanf(" %c",&c);
a[i][j]=c-'0';
}
}
nm=n*m;
ans=-1;
c.clear(nm+nm+3,nm+nm+2,nm+nm+3);
for (i=0;i<n;i++) {
for (j=0;j<m;j++) {
c.putedge(nm+nm+1,tran(i,j),1,0);
c.putedge(tran(i,j)+nm,nm+nm+3,1,0);
c.putedge(tran(i,j),tran(i,j)+nm,1,-20000);
}
}
for (i=0;i<n;i++) {
for (j=0;j<m;j++) {
for (k=i+1;k<n;k++) {
int tmp=-k+i+1;
if (a[i][j]==a[k][j]) tmp+=a[i][j];
c.putedge(tran(i,j)+nm,tran(k,j),1,-tmp);
}
for (k=j+1;k<m;k++) {
int tmp=-k+j+1;
if (a[i][j]==a[i][k]) tmp+=a[i][j];
c.putedge(tran(i,j)+nm,tran(i,k),1,-tmp);
}
}
}
curk=(n>m?m:n);
int edg=c.putedge(nm+nm+2,nm+nm+1,curk,0);
for (;curk<=kk;curk++) {
c.flow();
if (c.getFlow()==curk) {
int tmp=-(c.getCost()+20000*nm);
if (ans==-1||tmp>ans) ans=tmp;
}
c.b[edg].f++;
}
printf("Case %d : %d\n",t,ans);
}
return 0;
}