/*最小K路径覆盖的模型,用费用流或者KM算法解决, 构造二部图,X部有N*M个节点,源点向X部每个节点连一条边, 流量1,费用0,Y部有N*M个节点,每个节点向汇点连一条边,流量1, 费用0,如果X部的节点x可以在一步之内到达Y部的节点y,那么就连边x->y, 费用为从x格子到y格子的花费能量减去得到的能量,流量1, 再在X部增加一个新的节点,表示可以从任意节点出发K次,源点向其连边, 费用0,流量K,这个点向Y部每个点连边,费用0,流量1,最这个图跑最小费用最大流, 如果满流就是存在解,反之不存在,最小费用的相反数就是可以获得的最大能量 因为要求最小路径覆盖,n*m-maxflow<=k ,所以maxflow+k>=n*m,如果是满流的话就存在最小费用最大流可求出,否则*/ #include<stdio.h> #include<math.h> #include<string.h> #include<queue> using namespace std; #define inf 0x3fffffff #define N 500 struct node { int u,v,w,f,next; } bian[N*N*10]; char ss[N][N]; int ma[N][N]; int manha(int i,int j,int ii,int jj) { if(ma[i][j]==ma[ii][jj]) return ii-i+jj-j-1-ma[i][j]; return ii-i+jj-j-1; } /*模板*/ int dis[N],pre[N],head[N],visit[N],yong,maxflow; void init() { memset(head,-1,sizeof(head)); yong=0; } void build(int u,int v,int w,int f) { bian[yong].u=u; bian[yong].v=v; bian[yong].w=w; bian[yong].f=f; bian[yong].next=head[u]; head[u]=yong++; } void adde(int u,int v,int w,int f) { build(u,v,w,f); build(v,u,-w,0); } int min_cost(int s,int t) { int sum=0; while(1) { memset(visit,0,sizeof(visit)); memset(pre,-1,sizeof(pre)); for(int i=0; i<=t; i++) //注意是从0开始而不是从s开始 dis[i]=inf; queue<int>q; visit[s]=1;//必须是s q.push(s); dis[s]=0; while(!q.empty ()) { int u=q.front (); for(int index=head[u]; index!=-1; index=bian[index].next) { int v=bian[index].v; if(bian[index].f&&dis[v]>dis[u]+bian[index].w) { dis[v]=dis[u]+bian[index].w; pre[v]=index; if(!visit[v]) { visit[v]=1; q.push (v); } } } q.pop(); visit[u]=0;//是u } int i; if(dis[t]==inf) break; int minn=inf; i=pre[t]; while(i!=-1) { if(minn>bian[i].f) minn=bian[i].f; i=pre[bian[i].u]; } maxflow+=minn; sum=sum+minn*dis[t]; i=pre[t]; while(i!=-1) { bian[i].f-=minn; bian[i^1].f+=minn; i=pre[bian[i].u]; } } return sum; } /*最小费用最大流*/ int main() { int n,m,i,j,k,s,t,T,kk,r,l,su,index=0; scanf("%d",&T); while(T--) { init(); scanf("%d%d%d",&n,&m,&k); for(i=1; i<=n; i++) scanf("%s",ss[i]+1); for(i=1; i<=n; i++) for(j=1; j<=m; j++) ma[i][j]=ss[i][j]-'0'; s=0; kk=2*n*m+1; t=kk+1; for(i=1; i<=n*m; i++) adde(s,i,0,1); adde(s,kk,0,k); for(i=n*m+1; i<=n*m*2; i++) { adde(kk,i,0,1); adde(i,t,0,1); } for(i=1; i<=n; i++) for(j=1; j<=m; j++) { for(r=j+1; r<=m; r++) { int w=manha(i,j,i,r); adde((i-1)*m+j,(i-1)*m+r+n*m,w,1); } for(r=i+1; r<=n; r++) { int w=manha(i,j,r,j); adde((i-1)*m+j,(r-1)*m+j+n*m,w,1); } } maxflow=0; su=min_cost(s,t); printf("Case %d : ",++index); if(maxflow==n*m) printf("%d ",-su); else printf("%d ",-1); } return 0; }