题目链接:https://www.luogu.org/problem/P4013
对于第一问
把一个点拆成入点和出点,从入点到出点连一条容量1,费用0的边,表示每个点最多只能经过一次。
从S连向第一层的各点的入点,容量1,费用为负的点权。
从最后一层点的出点连向T,容量1,费用0。
从各个点的出点连向下次能到达点的入点,容量1,费用为负的目标点点权。
拆点保证点只经过一次,各边的容量1保证边只经过一次。
对于第二问
在第一问的基础上,取消拆点。
从最后一层点的出点连向T,容量inf,费用0。
对于第三问
在第二问的基础上,除了S连向第一层的边之外,把其余边的容量改为inf。
// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define pii pair<int,int>
#define mp make_pair
using namespace std;
const int N = 1e4+100;
int n,m,S,T,tot;
int head[N];
struct node{
int v,cap,cost,nxt;
}edge[int(2e5+100)];
int dis[N],pre[N],last[N],flow[N],maxflow,mincost; //pre:前驱结点 last:每个点所连的前一条边 flow:源点到该点的流量
bool vis[N];
void ae(int u,int v,int cap,int cost){ //前向星加边
edge[++tot] = node{v,cap,cost,head[u]};
head[u] = tot;
edge[++tot] = node{u,0,-cost,head[v]};
head[v] = tot;
}
bool spfa() {
memset(dis,0x7f,sizeof(dis));
memset(flow,0x7f,sizeof(flow)); //2e9
memset(vis,0,sizeof(vis));
deque<int> q;
q.push_back(S);
vis[S] = 1; dis[S] = 0; pre[T] = -1;
while(!q.empty()) {
int u = q.front();
q.pop_front();
vis[u] = 0;
for(int i = head[u]; ~i; i = edge[i].nxt) {
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;
last[v] = i;
flow[v] = min(flow[u],edge[i].cap);
if(!vis[v]) {
vis[v] = 1;
if(dis[v]<=dis[u]) q.push_front(v);
else q.push_back(v);
}
}
}
}
return pre[T] != -1;
}
void dinic(){
while(spfa()){
int now = T;
maxflow += flow[T];
mincost += flow[T]*dis[T];
while(now!=S) {
edge[last[now]].cap -= flow[T];
edge[last[now]^1].cap += flow[T];
now = pre[now];
}
}
return ;
}
void init() {
tot = -1;
maxflow = 0;
mincost = 0;
memset(head,-1,sizeof(head));
}
int hs[110][110];
int s[110][110];
int main() {
// freopen("a.txt","r",stdin);
// ios::sync_with_stdio(0);
cin>>m>>n;
int cnt = 0;
rep(i, 1, n)
rep(j, 1, m+i-1) {
cnt++;
hs[i][j] = cnt;
cin>>s[i][j];
}
init();
S = 0;
T = 2*cnt+1;
rep(i, 1, n)
rep(j, 1, m+i-1) {
ae(hs[i][j],hs[i][j]+cnt,1,0);
if(i==1) ae(S,hs[i][j],1,-s[i][j]);
if(i==n) ae(hs[i][j]+cnt,T,1,0);
else {
ae(hs[i][j]+cnt,hs[i+1][j],1,-s[i+1][j]);
ae(hs[i][j]+cnt,hs[i+1][j+1],1,-s[i+1][j+1]);
}
}
dinic();
cout<<-mincost<<endl;
init();
S = 0;
T = cnt+1;
rep(i, 1, n)
rep(j, 1, m+i-1) {
if(i==1) ae(S,hs[i][j],1,-s[i][j]);
if(i==n) ae(hs[i][j],T,1e9,0);
else {
ae(hs[i][j],hs[i+1][j],1,-s[i+1][j]);
ae(hs[i][j],hs[i+1][j+1],1,-s[i+1][j+1]);
}
}
dinic();
cout<<-mincost<<endl;
init();
S = 0;
T = cnt+1;
rep(i, 1, n)
rep(j, 1, m+i-1) {
if(i==1) ae(S,hs[i][j],1,-s[i][j]);
if(i==n) ae(hs[i][j],T,1e9,0);
else {
ae(hs[i][j],hs[i+1][j],1e9,-s[i+1][j]);
ae(hs[i][j],hs[i+1][j+1],1e9,-s[i+1][j+1]);
}
}
dinic();
cout<<-mincost<<endl;
return 0;
}