费用流,拆点
//http://www.cnblogs.com/IMGavin/
#include <iostream>
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#include <algorithm>
using namespace std;
typedef long long LL;
#define gets(A) fgets(A, 1e8, stdin)
const int INF = 0x3F3F3F3F, N = 1008, MOD = 1003, M = 2000000;
const double EPS = 1e-6;
int val[N][N];
struct Node{
int u, v, cap, cost;
int next;
}edge[M];//有向图,u到v的容量,费用
int tot;
int head[N], pre[N], path[N], dis[N];
bool inq[N];
int m, n;
void init(){
tot = 0;
memset(head, -1, sizeof(head));
}
void add(int u, int v, int cost, int cap){
edge[tot].u = u;
edge[tot].v = v;
edge[tot].cap = cap;
edge[tot].cost = cost;
edge[tot].next = head[u];
head[u] = tot++;
edge[tot].u = v;
edge[tot].v = u;
edge[tot].cap = 0;
edge[tot].cost = -cost;
edge[tot].next = head[v];
head[v] = tot++;
}
bool SPFA(int st, int des){//计算最小费用
memset(inq, 0, sizeof(inq));
memset(dis, 0x3f, sizeof(dis));
queue <int> q;
q.push(st);
dis[st] = 0;
inq[st] = true;
while(!q.empty()){
int u = q.front();
q.pop();
inq[u] = false;
for(int i = head[u]; ~i; i = edge[i].next){
int v = edge[i].v;
if(edge[i].cap > 0 && dis[v] > dis[u] + edge[i].cost){
dis[v] = dis[u] + edge[i].cost;
pre[v] = u;
path[v] = i;
if(!inq[v]){
inq[v] = true;
q.push(v);
}
}
}
}
return dis[des] < INF;
}
int EdmondsKarp(int st, int des){//最小费用最大流
int mincost = 0, flow = 0;//最小费用与流量
while(SPFA(st, des)){
int f = INF;
for(int i = des; i != st; i = pre[i]){
if(f > edge[path[i]].cap){
f = edge[path[i]].cap;
}
}
for(int i = des; i != st; i = pre[i]){
edge[path[i]].cap -= f;
edge[path[i]^1].cap += f;
}
mincost += f * dis[des];
flow += f;
}
return mincost;
}
int cal1(){
init();
int tot = n * m + n * (n -1) / 2;
int st = 0, des = tot * 2 + 1;
for(int i = 0; i < n; i++){
for(int j = 0; j < m + i; j++){
int u = i * m + i * (i - 1) / 2 + j + 1;
add(u, u + tot, -val[i][j], 1);
}
}
for(int i = 0; i < n - 1; i++){
for(int j = 0; j < m + i; j++){
int u = i * m + i * (i - 1) / 2 + j + 1;
int v = (i + 1) * m + i * (i + 1) / 2 + j + 1;
add(u + tot, v, 0, 1);
add(u + tot, v + 1, 0, 1);
}
}
for(int i = 1; i <= m; i++){
add(st, i, 0, 1);
}
for(int i = 0; i < n + m - 1; i++){
int u = (n - 1) * m + (n - 1) * (n - 2) / 2 + i + 1;
add(u + tot, des, 0, 1);
}
return -EdmondsKarp(st, des);
}
int cal2(){
init();
int tot = n * m + n * (n -1) / 2;
int st = 0, des = tot * 2 + 1;
for(int i = 0; i < n; i++){
for(int j = 0; j < m + i; j++){
int u = i * m + i * (i - 1) / 2 + j + 1;
add(u, u + tot, -val[i][j], INF);
}
}
for(int i = 0; i < n - 1; i++){
for(int j = 0; j < m + i; j++){
int u = i * m + i * (i - 1) / 2 + j + 1;
int v = (i + 1) * m + i * (i + 1) / 2 + j + 1;
add(u + tot, v, 0, 1);
add(u + tot, v + 1, 0, 1);
}
}
for(int i = 1; i <= m; i++){
add(st, i, 0, 1);
}
for(int i = 0; i < n + m - 1; i++){
int u = (n - 1) * m + (n - 1) * (n - 2) / 2 + i + 1;
add(u + tot, des, 0, INF);
}
return -EdmondsKarp(st, des);
}
int cal3(){
init();
int tot = n * m + n * (n -1) / 2;
int st = 0, des = tot * 2 + 1;
for(int i = 0; i < n; i++){
for(int j = 0; j < m + i; j++){
int u = i * m + i * (i - 1) / 2 + j + 1;
add(u, u + tot, -val[i][j], INF);
}
}
for(int i = 0; i < n - 1; i++){
for(int j = 0; j < m + i; j++){
int u = i * m + i * (i - 1) / 2 + j + 1;
int v = (i + 1) * m + i * (i + 1) / 2 + j + 1;
add(u + tot, v, 0, INF);
add(u + tot, v + 1, 0, INF);
}
}
for(int i = 1; i <= m; i++){
add(st, i, 0, 1);
}
for(int i = 0; i < n + m - 1; i++){
int u = (n - 1) * m + (n - 1) * (n - 2) / 2 + i + 1;
add(u + tot, des, 0, INF);
}
return -EdmondsKarp(st, des);
}
int main(){
while(cin >> m >> n){
for(int i = 0; i < n; i++){
for(int j = 0; j < m + i; j++){
scanf("%d", &val[i][j]);
}
}
cout<<cal1()<<endl;
cout<<cal2()<<endl;
cout<<cal3()<<endl;
}
return 0;
}