题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4862
主要是构图,然后跑一下最小费用最大流,判断是不是满流,是的话答案就是费用的相反数,否则就为-1
构造二部图,X部n*m个点表示从[i,j]这个点走到Y部的点,Y部n*m个点表示从X部的点走到[i,j]
从源点到X部的每一个点连一条边,流量为1,费用为0,从Y部的每一个点到汇点连一条边,流量为1,费用为0
从X部的每一个点到Y部它能一步到达的点连一条边,流量为1,费用为-(获得的能量-花费),因为求最大值,所以取反
在X部添加一个点p,从源点到p连一条边,流量为K,费用为0,从p到Y部每一个点连一条边,流量为1,费用为0
表示其中的K个点可以为起点而不用从其他的点到达
#include <iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define INF 0x7fffffff
#define MAXN 505
#include<queue>
#define MAXE 10005
using namespace std;
int net[MAXN],size;
struct EDGE{
int v,next,cap,cost;
}e[MAXE];
void init(){
size=0;
memset(net,-1,sizeof(net));
}
void addedge(int u,int v,int cap,int cost){
e[size].v=v;e[size].cap=cap;e[size].cost=cost;e[size].next=net[u];net[u]=size++;
e[size].v=u;e[size].cap=0;e[size].cost=-cost;e[size].next=net[v];net[v]=size++;
}
int nv,dist[MAXN],pre[MAXN],pe[MAXN];
bool hash[MAXN];
queue<int> q;
bool spfa(int s,int t){
while(!q.empty())
q.pop();
memset(hash,0,sizeof(hash));
memset(pre,-1,sizeof(pre));
for(int i=0;i<nv;i++)
dist[i]=INF;
dist[s]=0;
hash[s]=1;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
hash[u]=0;
for(int i=net[u];i!=-1;i=e[i].next){
int v=e[i].v;
if(e[i].cap&&dist[v]>dist[u]+e[i].cost){
dist[v]=e[i].cost+dist[u];
pre[v]=u;
pe[v]=i;
if(hash[v]==0){
hash[v]=1;
q.push(v);
}
}
}
}
if(pre[t]==-1)
return false;
return true;
}
int MCMF(int s,int t,int need){
int max_flow=0;
int min_cost=0;
while(spfa(s,t)){
int aug=INF;
for(int v=t;v!=s;v=pre[v]){
aug=min(aug,e[pe[v]].cap);
min_cost+=e[pe[v]].cost;
}
max_flow+=aug;
for(int v=t;v!=s;v=pre[v]){
e[pe[v]].cap-=aug;
e[pe[v]^1].cap+=aug;
}
}
if(max_flow<need)
return -1;
return -min_cost;
}
int main()
{
int t,n,m,ics,k;
char str[15];
int mp[13][13];
scanf("%d",&t);
for(ics=1;ics<=t;ics++){
scanf("%d%d%d",&n,&m,&k);
init();
for(int i=0;i<n;i++){
scanf("%s",str);
for(int j=0;j<m;j++){
mp[i][j]=str[j]-'0';
}
}
int tmp;
int s=n*m*2,t=n*m*2+1,p=n*m*2+2;
nv=p+1;
addedge(s,p,k,0);
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
addedge(s,i*m+j,1,0);
addedge(n*m+i*m+j,t,1,0);
addedge(p,n*m+i*m+j,1,0);
for(int k=j+1;k<m;k++){
tmp=mp[i][j]==mp[i][k]?mp[i][j]:0;
addedge(i*m+j,n*m+i*m+k,1,-tmp+(k-j)-1);
}
for(int k=i+1;k<n;k++){
tmp=mp[i][j]==mp[k][j]?mp[i][j]:0;
addedge(i*m+j,n*m+k*m+j,1,-tmp+(k-i)-1);
}
}
}
printf("Case %d : %d\n",ics,MCMF(s,t,n*m));
}
return 0;
}