[Vijos 1143]三取方格数

时间:2023-03-09 22:02:08
[Vijos 1143]三取方格数

Description

设有N*N的方格图,我们将其中的某些方格填入正整数,
而其他的方格中放入0。

某人从图得左上角出发,可以向下走,也可以向右走,直到到达右下角。

在走过的路上,他取走了方格中的数。(取走后方格中数字变为0)
此人从左上角到右下角共走3次,试找出3条路径,使得取得的数总和最大。

Input

第一行:N (4<=N<=20)
接下来一个N*N的矩阵,矩阵中每个元素不超过80,不小于0

Output

一行,表示最大的总和。

Sample Input

4
1 2 3 4
2 1 3 4
1 2 3 4
1 3 2 4

Sample Output

39

题解(转载)

->原文地址<-

$DP$好题。

这里给出费用流的做法:

拆点建图,每一个点都拆成两个点,在这里就称为出点和入点。

出点和入点建两条边,一条费用为$s[i][j]$,流量为$1$;一条费用为$0$,流量为$inf$。(分别表示选择这个点和从这个点上经过)

将$(i,j)$的出点分别和$(i+1,j)$$(i,j+1)$的入点建边,流量为$inf$,费用为$0$。(表示行进)

跑一边最大费用最大流就可以了。

 #include <set>
#include <map>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define LL long long
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
const int INF = ~0u>>; int n;
int a[][];
struct tt{
int to, cost, next, cap;
}edge[];
int path[], top = -;
void Add(int u, int v, int cost, int cap);
int sta = , fin = ;
int min_cost_flow();
int SPFA(); int main(){
memset(path, -, sizeof(path));
scanf("%d", &n);
for (int i = ; i < n; i++)
for (int j = ; j < n; j++)
scanf("%d", &a[i][j]);
for (int i = ; i < n; i++)
for (int j = ; j < n; j++){
Add(i*n+j, (i+n)*n+j, a[i][j], );
Add(i*n+j, (i+n)*n+j, , INF);
if (i != n-) Add((i+n)*n+j, (i+)*n+j, , INF);
if (j != n-) Add((i+n)*n+j, i*n+j+, , INF);
}
Add(sta, , , );
Add((*n-)*n+n-, fin, ,);
printf("%d\n", min_cost_flow());
return ;
} void Add(int u, int v, int cost, int cap){
edge[++top].to = v;
edge[top].cost = cost;
edge[top].cap = cap;
edge[top].next = path[u];
path[u] = top;
edge[++top].to = u;
edge[top].cost = -cost;
edge[top].cap = ;
edge[top].next = path[v];
path[v] = top;
}
int min_cost_flow(){
int tolcost = ;
int tmp;
while (tmp = SPFA()) tolcost += tmp;
return tolcost;
}
int SPFA(){
int dist[];
memset(dist, , sizeof(dist)); dist[sta] = ; dist[fin] = -INF;
bool vis[] = {}; vis[sta] = ;
queue<int>Q;
while (!Q.empty()) Q.pop();
Q.push(sta);
int pre[] = {};
while (!Q.empty()){
   int u = Q.front(); Q.pop(); vis[u]=;
   for (int i = path[u]; i != -; i = edge[i].next){
   int v = edge[i].to;
   if (dist[v] < dist[u]+edge[i].cost && edge[i].cap > ){
     dist[v] = dist[u]+edge[i].cost;
     pre[v] = i;
     if (!vis[v]){
     vis[v] = ;
     Q.push(v);
     }
   }
   }
}
if (dist[fin] == -INF) return ;
int minflow = INF;
for (int i = fin; i != sta; i = edge[pre[i]^].to)
   minflow = Min(minflow, edge[pre[i]].cap);
for (int i = fin; i != sta; i = edge[pre[i]^].to)
   edge[pre[i]].cap -= minflow,
   edge[pre[i]^].cap += minflow;
return dist[fin];
}