题目大意:
有n*m个方格,每个方格都一个的十进制一位的数。你可以操作K次。
对于每一次操作,你可以选择一个出发点向下或向右Jump。跳的花费是|x1-x2|+|y1-y2|-1的能量 。如果你跳的这两个位置上数字相同,那么你就会获得数字表示的能量值。
对于每一次操作,你可以这样跳任意次 ,但是每个位置只能经过一次在这K次操作中。
初始能量值是0,当操作完成后,如果n*m个方格没有都经过过,输出“-1”,否则输出可以得到的最大能量值。
思路:既然是任意选一个那么我们可以设置一个中间点n*m+1,然后将整个图分成两部分
x Y
1~n*m n*m+1 n*m+1 ~ 2*n*m+1
用源点连接n*m+1,和X部分的所有点,然后n*m+1连Y部分,且Y部分连接汇点,再是拆点将X于Y相连接在处理费用的时候我们可以求最小消耗 = 最大得分
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
#define inf 0x3f3f3f3f
#define LL __int64
using namespace std;
const int N = 8000;
int sum,head[N],cost,flow;
struct node{
int to,c,w,next;
}q[N*50];
int mp[20][20],cur[N],f[N],dis[N];
int st,ed;
bool vis[N];
void Add(int u,int v,int cap,int cost){
q[sum].to=v;
q[sum].w=cap;
q[sum].c=cost;
q[sum].next=head[u];
head[u]=sum++;
q[sum].to=u;
q[sum].w=0;
q[sum].c=-cost;
q[sum].next=head[v];
head[v]=sum++;
}
int SPFA(){
memset(vis,false,sizeof(vis));
memset(dis,inf,sizeof(dis));
queue<int>Q;
while(!Q.empty())
Q.pop();
Q.push(st);
cur[st] = -1;
f[st] = inf;
dis[st] = 0;
while(!Q.empty()){
int u = Q.front();
Q.pop();
vis[u] = false;
for(int i = head[u];~i;i=q[i].next ){
int v = q[i].to;
if(dis[v] > dis[u] + q[i].c&&q[i].w ){
dis[v] = dis[u] + q[i].c;
cur[v] = i;
f[v] = min(f[u],q[i].w);
if(!vis[v]){
vis[v] = true;
Q.push(v);
}
}
}
}
if(dis[ed] == inf)
return 0;
flow += f[ed];
cost += f[ed]*dis[ed];
for(int i = cur[ed];~i;i = cur[q[i^1].to ]){
q[i].w -= f[ed];
q[i^1].w += f[ed];
}
return 1;
}
char str[20];
int main(){
int n,m,i,j,k,cla;
scanf("%d",&cla);
for(int zu = 1;zu <= cla;++ zu){
scanf("%d%d%d",&n,&m,&k);
cost = flow = 0;
sum = 0;
memset(head,-1,sizeof(head));
for(i = 0;i < n;++ i){
scanf("%s",str);
for(j = 0;j < m;++ j){
mp[i][j] = str[j] - '0';
}
}
st = 2*n*m+10;
ed = 2*n*m+11;
for(i = 1;i <= n*m;++ i){
Add(st,i,1,0);
Add(n*m+1+i,ed,1,0);
Add(n*m+1,n*m+1+i,1,0);
}
Add(st,n*m+1,k,0);int tmp;
for(i = 0;i < n;++ i){
for(j = 0;j < m;++ j){
for(k = j+1;k < m;++ k){
tmp = 0;
if( mp[i][j] == mp[i][k] )
tmp = mp[i][j];
Add(i*m+j+1,m*n+1+i*m+k+1,1,k-j-1-tmp );
}
for(k = i+1;k < n;++ k){
tmp = 0;
if( mp[i][j] == mp[k][j] ){
tmp = mp[i][j];
}
Add(i*m+j+1,m*n+1+k*m+j+1,1,k-i-1-tmp );
}
}
}
printf("Case %d : ",zu);
while(SPFA());
if(flow == n*m)
printf("%d\n",-cost);
else
puts("-1");
}
return 0;
}