https://vjudge.net/contest/166969#problem/L
第一次写这种题。。
感觉还是很巧妙的。先求得花费最小的增广路,然后在进行增广路径。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <cstring>
/*这道题主要是求,一个花费。
可以知道是费用流。
固定套路,先求最小花费的那个路,在那个条件下求最大流。
关键是建边的过程。
*/
using namespace std;
const int maxn=5005;
int m,n;
int s,t;
const long long INF=1e15;
struct Node
{ int to;//到达的点
int next;//邻接
long long flow;//流
long long cap;//容
long long cost;
}node[1000005];
int head[maxn];
long long dis[maxn];
int pre[maxn];
int vis[maxn];
int len;
int N;
void add(int a,int b,long long c){
node[len].to=b;
node[len].cap=1;
node[len].flow=0;
node[len].next=head[a];
node[len].cost=c;
head[a]=len++;
node[len].to=a;
node[len].cap=0;
node[len].flow=0;
node[len].next=head[b];
node[len].cost=-c;
head[b]=len++;
}
bool spfa (int s, int t) {
queue <int> q;
for (int i = 0; i < N; i++) {
dis[i] = INF;
vis[i] = 0;
pre[i] = -1;
}
dis[s] = 0;
vis[s] = 1;
q.push (s);
while (!q.empty ()) {
int u = q.front (); q.pop ();
vis[u] = 0;
for (int i = head[u]; i != -1; i = node[i].next) {
int v = node[i].to;
if (node[i].cap > node[i].flow && dis[v] > dis[u]+node[i].cost) {
dis[v] = dis[u]+node[i].cost;
pre[v] = i;
if (!vis[v]) {
vis[v] = 1;
q.push (v);
}
}
}
}
if (pre[t] == -1)
return 0;
else
return 1;
}
int MCMF (int s, int t, long long &cost) {
long long flow = 0;
cost = 0;
while (spfa (s, t)) {
long long Min = INF;
for (int i = pre[t]; i != -1; i = pre[node[i^1].to]) {
if (Min > node[i].cap-node[i].flow) {
Min = node[i].cap-node[i].flow;
}
}
for (int i = pre[t]; i != -1; i = pre[node[i^1].to]) {
node[i].flow += Min;
node[i^1].flow -= Min;
cost += node[i].cost*Min;
}
flow += Min;
}
return flow;
}
void init()
{ memset(head,-1,sizeof(head));
len=0;
}
int get(int a,int b){
return a*n+b;
}
int main()
{ int T;
int num;
scanf("%d",&T);
for(int ttt=1;ttt<=T;ttt++){
int max1=0;
scanf("%d%d",&m,&n);
t=2*m*n+1;
s=2*m*n;
N=2*m*n+2;
init();
for(int i=0;i<m;i++)
for(int j=0;j<n;j++){
scanf("%d",&num);
if(num==0){
add(s,get(i,j),0);
add(get(i,j)+m*n,t,0);
max1++;
}
else if(num&1){
add(s,get(i,j),0);
max1++;
}
else
add(get(i,j)+n*m,t,0);
}
for(int i=0;i<m-1;i++)
for(int j=0;j<n;j++){
scanf("%d",&num);
add(get(i,j),get(i+1,j)+m*n,num);
add(get(i+1,j),get(i,j)+m*n,num);
}
for(int i=0;i<m;i++)
for(int j=0;j<n-1;j++){
scanf("%d",&num);
add(get(i,j),get(i,j+1)+n*m,num);
add(get(i,j+1),get(i,j)+m*n,num);
}
long long cost=0;
printf("Case #%d: ",ttt);
int ans=MCMF(s,t,cost);
if(ans!=max1){
puts("-1");
}
else
printf("%lld\n",cost);
}
return 0;
}