中文题干
三个情况,就是三种建图的方式,而且三种建图越来越简单。
虽说要建的图不太一样,但是本质上只是拆点不拆点,以及边的权值和流量选择的问题
脑洞:
三个规则:
第一种::: 所有的点和边都不能相交,我们要进行拆点操作,每个点第一部分连接到上一层的点(第一层就连接源点)。每个点的第二部分连接到下一层的点(如果是最后一层就连接到汇点上去)。中间的所有边,他的流量都是一,因为都只能走一次。而这些边中,只有同一个点的两个部分相互连接的那条边才有权值,为这个点的权值。
第二种:::不拆点啦,但是所有的边还都只能走一次,所以,除了拆边操作意外,其他的都是一行的。至于权值,我们就赋到每个点的后面一条边,即从这个点出发到达另外的点的那条边,这样才知道我们走的是哪条边。
第三种::: 这种就更加简单了呃, 边都可以重复走,那我们就全部给成INF就行了,但要注意的是,源点到第一层上的点的这些边的流量永远是1。
嗯嗯 ,就这样, 代码建图都是复制粘贴,改变一些细节。。。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#define len 100010
#define MAXN 2020
#define INF 0x3f3f3f3f
using namespace std;
struct edge{
int u, v, f, c, nxt;
};
edge e[len];
int head[MAXN], hcnt;
int dis[MAXN], inq[MAXN];
int pre[len], M[MAXN][MAXN];
int S, T;
int m, n;
void Init(){
memset(head, -1, sizeof (head));
hcnt = 0;
}
void adde(int u, int v, int f, int c){
e[hcnt].u = u; e[hcnt].v = v; e[hcnt].c = c; e[hcnt].f = f;
e[hcnt].nxt = head[u]; head[u] = hcnt ++;
e[hcnt].u = v; e[hcnt].v = u; e[hcnt].c = -c; e[hcnt].f = 0;
e[hcnt].nxt = head[v]; head[v] = hcnt ++;
}
bool spfa(){
memset(dis, INF, sizeof (dis));
memset(inq, 0, sizeof (inq));
memset(pre, -1, sizeof (pre));
queue <int> q;
dis[S] = 0; q.push(S);
inq[S] ++;
while (!q.empty()){
int h = q.front(); q.pop();
for (int i=head[h]; ~i; i=e[i].nxt){
int v = e[i].v;
if (dis[v] > dis[h] + e[i].c && e[i].f > 0){
dis[v] = dis[h] + e[i].c;
pre[v] = i;
if (!inq[v]){
inq[v] ++;
q.push(v);
}
}
}
inq[h] = 0;
}
if (pre[T] == -1) return false;
return true;
}
int dfs(){
int res = 0;
while (spfa()){
int d = INF;
for (int i=pre[T]; ~i; i=pre[e[i].u])
if (d > e[i].f) d = e[i].f;
for (int i=pre[T]; ~i; i=pre[e[i].u]){
e[i].f -= d;
e[i^1].f += d;
res += d * e[i].c;
}
}
return res;
}
int get(int i, int j){
return (m + m + i - 2) * (i - 1) / 2 + j;
}
int main(){
scanf("%d%d", &m, &n);
Init();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m + i - 1; j++)
scanf("%d", &M[i][j]);
//first:::
int sum = (m+m+n-1)*n/2;
S = 0; T = sum * 2 + 1;
for (int i=1; i<=n; i++){
for (int j=1; j<=m+i-1; j++){
adde(get(i, j), get(i, j) + sum, 1, -M[i][j]);
if (i == 1)
adde(S, get(i, j), 1, 0);
if (i < n){
adde(sum + get(i, j), get(i+1, j), 1, 0);
adde(sum + get(i, j), get(i+1, j+1), 1, 0);
}
if (i == n)
adde(sum + get(i, j), T, 1, 0);
}
}
int ans = dfs();
printf ("%d\n", -ans);
//second:::
Init();
S = 0; T = sum + 1;
for (int i=1; i<=n; i++){
for (int j=1; j<=m+i-1; j++){
if (i == 1)
adde(S, get(i, j), 1, 0);
if (i < n){
adde(get(i, j), get(i+1, j), 1, -M[i][j]);
adde(get(i, j), get(i+1, j+1), 1, -M[i][j]);
}
if (i == n)
adde(get(i, j), T, INF, -M[i][j]);
}
}
ans = dfs();
printf ("%d\n", -ans);
//third:::
Init();
S = 0; T = sum + 1;
for (int i=1; i<=n; i++){
for (int j=1; j<=m+i-1; j++){
if (i == 1)
adde(S, get(i, j), 1, 0);
if (i < n){
adde(get(i, j), get(i+1, j), INF, -M[i][j]);
adde(get(i, j), get(i+1, j+1), INF, -M[i][j]);
}
if (i == n)
adde(get(i, j), T, INF, -M[i][j]);
}
}
ans = dfs();
printf ("%d\n", -ans);
return 0;
}