codevs 1913 数字梯形问题 费用流
给你一个数字梯形, 最上面一层m个数字, 然后m+1,......m+n-1个。 n是层数。 在每个位置, 可以向左下或右下走。然后让你从最顶端的m个数字开始, 走出m条路径, 使得路过的数字总和最大。
给你三种规则, 第一种是,m条路径完全不能相交。 第二种是可以在数字处相交。 第三种是可以在数字或边的地方相交, 相当于没有限制。让你输出在这三种情况下的最大值分别是多少。
第一种, 因为完全不能相交, 所以我们将每个点拆成两个点x, x', x向x'连一条权值为1, 费用为-a[i][j]的边。 x'向可以到达的y连一条权值1, 费用0的边。 这样保证只走一次。
第二种, 可以在点的地方相交, 那x向x'连的那条边权值就可以放松为m。 其他不变。
第三种, 不光x向x'连的边权值可以放松, x'向y连得边权值也可以放松为m。
然后就可以得出答案了。
#include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <complex> #include <cmath> #include <map> #include <set> #include <string> #include <queue> #include <stack> #include <bitset> using namespace std; #define pb(x) push_back(x) #define ll long long #define mk(x, y) make_pair(x, y) #define lson l, m, rt<<1 #define mem(a) memset(a, 0, sizeof(a)) #define rson m+1, r, rt<<1|1 #define mem1(a) memset(a, -1, sizeof(a)) #define mem2(a) memset(a, 0x3f, sizeof(a)) #define rep(i, n, a) for(int i = a; i<n; i++) #define fi first #define se second typedef complex <double> cmx; typedef pair<int, int> pll; const double PI = acos(-1.0); const double eps = 1e-8; const int mod = 1e9+7; const int inf = 1061109567; const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} }; const int maxn = 2e5+5; int num, head[maxn*2], s, t, n, nn, dis[maxn], flow, cost, cnt, cap[maxn], q[maxn], cur[maxn], vis[maxn], m, a[21][50]; struct node { int to, nextt, c, w; node(){} node(int to, int nextt, int c, int w):to(to), nextt(nextt), c(c), w(w) {} }e[maxn*2]; int spfa() { int st, ed; st = ed = 0; mem2(dis); ++cnt; dis[s] = 0; cap[s] = inf; cur[s] = -1; q[ed++] = s; while(st<ed) { int u = q[st++]; vis[u] = cnt-1; for(int i = head[u]; ~i; i = e[i].nextt) { int v = e[i].to, c = e[i].c, w = e[i].w; if(c && dis[v]>dis[u]+w) { dis[v] = dis[u]+w; cap[v] = min(c, cap[u]); cur[v] = i; if(vis[v] != cnt) { vis[v] = cnt; q[ed++] = v; } } } } if(dis[t] == inf) return 0; cost += dis[t]*cap[t]; flow += cap[t]; for(int i = cur[t]; ~i; i = cur[e[i^1].to]) { e[i].c -= cap[t]; e[i^1].c += cap[t]; } return 1; } int mcmf() { flow = cost = 0; while(spfa()) ; return cost; } void add(int u, int v, int c, int val) { e[num] = node(v, head[u], c, val); head[u] = num++; e[num] = node(u, head[v], 0, -val); head[v] = num++; } void init() { mem1(head); num = cnt = 0; mem(vis); } int getnum(int x, int y) { return (m+(x-1)+m)*(x)/2+y+1; } void solve() { init(); t = 1+(2*m+n-1)*n; s = 0; int sum = (2*m+n-1)*n/2; for(int i = 0; i < n; i++) { for(int j = 0; j < m+i; j++) { if(!i) { add(s, j+1, 1, 0); } int x = getnum(i, j); add(x, x+sum, 1, -a[i][j]); if(i != n-1) { int nxt = getnum(i+1, j); add(x+sum, nxt, 1, 0); add(x+sum, nxt+1, 1, 0); } if(i == n-1) { add(x+sum, t, 1, 0); } } } cout<<-mcmf()<<endl; init(); for(int i = 0; i < n; i++) { for(int j = 0; j < m+i; j++) { if(!i) { add(s, j+1, 1, 0); } int x = getnum(i, j); add(x, x+sum, m, -a[i][j]); if(i != n-1) { int nxt = getnum(i+1, j); add(x+sum, nxt, 1, 0); add(x+sum, nxt+1, 1, 0); } if(i == n-1) { add(x+sum, t, m, 0); } } } cout<<-mcmf()<<endl; init(); for(int i = 0; i < n; i++) { for(int j = 0; j < m+i; j++) { if(!i) { add(s, j+1, 1, 0); } int x = getnum(i, j); add(x, x+sum, m, -a[i][j]); if(i < n-1) { int nxt = getnum(i+1, j); add(x+sum, nxt, m, 0); add(x+sum, nxt+1, m, 0); } else { add(x+sum, t, m, 0); } } } cout<<-mcmf()<<endl; } int main() { cin>>m>>n; for(int i = 0; i < n; i++) { for(int j = 0; j < m+i; j++) { scanf("%d", &a[i][j]); } } solve(); return 0; }