列表

详情


NC213828. [网络流24题]数字梯形问题

描述

给定一个由n 行数字组成的数字梯形如下图所示。梯形的第一行有m 个数字。从梯形的顶部的m 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径。
规则1:从梯形的顶至底的m条路径互不相交。
规则2:从梯形的顶至底的m条路径仅在数字结点处相交。
规则3:从梯形的顶至底的m条路径允许在数字结点相交或边相交。

对于给定的数字梯形,分别按照规则1,规则2,和规则3 计算出从梯形的顶至底的m条路径,使这m条路径经过的数字总和最大。

输入描述

第1 行中有2个正整数m和n(m,n<=20),分别表示数字梯形的第一行有m个数字,共有n 行。接下来的n 行是数字梯形中各行的数字。
第1 行有m个数字,第2 行有m+1 个数字,…。

输出描述

程序运行结束时,将按照规则1,规则2,和规则3 计算出的最大数字总和输出。每行一个最大总和。

示例1

输入:

2 5
2 3
3 4 5
9 10 9 1
1 1 10 1 1
1 1 10 12 1 1

输出:

66
75
77

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 3ms, 内存消耗: 512K, 提交时间: 2023-08-04 15:48:44

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

struct {
	int v,w,c,nxt;
}e[200010];
int head[200010],cnt=1;
int n,m,s,t;
int a[2100][2100],sum[2100][2010];
void add(int u,int v,int w,int c)
{
	e[++cnt]={v,w,c,head[u]};
	head[u]=cnt;
}

int pre[2100],dis[2100],inq[2100];
bool spfa()
{
	for(int i=s;i<=t;i++)
	{
		pre[i]=-1;
		dis[i]=-1e9;
		inq[i]=0;
	}

	queue<int>q;
	q.push(s);
	inq[s]=1;
	dis[s]=0;
	while(q.size())
	{
		//cout<<"sp\n";
		int u=q.front();
		q.pop();
		inq[u]=0;

		for(int i=head[u];i>0;i=e[i].nxt){
			int v=e[i].v,c=e[i].c;
			if(e[i].w>0&&dis[v]<dis[u]+c){
				dis[v]=dis[u]+c;
				pre[v]=i;
				if(!inq[v]){
					inq[v]=1;
					q.push(v);
				}
			}
		}
	}
	return dis[t]!=-1e9;
}

int mincost()
{
	int flow=0,cost=0;
	while(spfa())
	{

		int f=1e9,u=t;

		while(pre[u]!=-1){
			f=min(f,e[pre[u]].w);
			u=e[pre[u]^1].v;
		}

		u=t;
		while(pre[u]!=-1){
			e[pre[u]].w-=f;
			e[pre[u]^1].w+=f;
			u=e[pre[u]^1].v;
		}
		
		cost+=f*dis[t];
		flow+=f;

	}

	return cost;
}

void clear()
{
	for(int i=0;i<=t;i++)
		head[i]=0;
	for(int i=1;i<=cnt;i++)
		e[i].v=e[i].c=e[i].w=e[i].nxt=0;
} 

int main()
{
	cin>>m>>n;
	int tt=n*m+n*(n-1)/2;//注意s、t的实际范围;
	s=0,t=tt*2+1;
	
	int qq=0;
	for(int i=1,k=0;i<=n;i++,k++)
		for(int j=1;j<=m+k;j++)
		{
			cin>>a[i][j];
			sum[i][j]=++qq;
		}

	for(int i=1;i<=m;i++){
		add(s,sum[1][i],1,0);
		add(sum[1][i],s,0,0);
	}
	//建图要考虑清楚,不能在建图环节出现错误!!!;
	qq=0;int k=0;
	for(int i=1;i<n;i++,k++)
		for(int j=1;j<=k+m;j++){
			add(sum[i][j],sum[i][j]+tt,1,a[i][j]);
			add(sum[i][j]+tt,sum[i][j],0,-a[i][j]);

			add(sum[i][j]+tt,sum[i+1][j],1,0);
			add(sum[i+1][j],sum[i][j]+tt,0,0);

			add(sum[i][j]+tt,sum[i+1][j+1],1,0);
			add(sum[i+1][j+1],sum[i][j]+tt,0,0);
			++qq;
		}

	for(int i=1;i<=m+k;i++){
		add(sum[n][i],sum[n][i]+tt,1,a[n][i]);
		add(sum[n][i]+tt,sum[n][i],0,-a[n][i]);

		add(sum[n][i]+tt,t,1,0);
		add(t,sum[n][i]+tt,0,0);
	}

	cout<<mincost()<<'\n';

	clear();

	s=0,t=tt+1;
	for(int i=1;i<=m;i++){
		add(s,sum[1][i],1,a[1][i]);
		add(sum[1][i],s,0,-a[1][i]);
	}
	//建图要考虑清楚,不能在建图环节出现错误!!!;
	 k=0;
	for(int i=1;i<n;i++,k++)
		for(int j=1;j<=k+m;j++){

			add(sum[i][j],sum[i+1][j],1,a[i+1][j]);
			add(sum[i+1][j],sum[i][j],0,-a[i+1][j]);

			add(sum[i][j],sum[i+1][j+1],1,a[i+1][j+1]);
			add(sum[i+1][j+1],sum[i][j],0,-a[i+1][j+1]);
		}

	for(int i=1;i<=m+k;i++){
		add(sum[n][i],t,1e9,0);
		add(t,sum[n][i],0,0);
	}
	cout<<mincost()<<"\n";


	clear();

	s=0,t=tt+1;
	for(int i=1;i<=m;i++){
		add(s,sum[1][i],1,a[1][i]);
		add(sum[1][i],s,0,-a[1][i]);
	}
	//建图要考虑清楚,不能在建图环节出现错误!!!;
	 k=0;
	for(int i=1;i<n;i++,k++)
		for(int j=1;j<=k+m;j++){

			add(sum[i][j],sum[i+1][j],1e9,a[i+1][j]);
			add(sum[i+1][j],sum[i][j],0,-a[i+1][j]);

			add(sum[i][j],sum[i+1][j+1],1e9,a[i+1][j+1]);
			add(sum[i+1][j+1],sum[i][j],0,-a[i+1][j+1]);
		}

	for(int i=1;i<=m+k;i++){
		add(sum[n][i],t,1e9,0);
		add(t,sum[n][i],0,0);
	}
	cout<<mincost()<<"\n";

	return 0;

}

C++(clang++ 11.0.1) 解法, 执行用时: 3ms, 内存消耗: 400K, 提交时间: 2022-11-09 17:15:10

#include <iostream>
#include <cstring>

using namespace std;

const int N = 1200, M = 4000, INF = 1e8;

int e[M], ne[M], f[M], w[M], h[N], idx;
int d[N], q[N], pre[N], incf[N];
int n, m, S, T, cnt;
bool vis[N];
int id[50][50], s[50][50];

void insert(int u, int v, int c, int d) {
    e[idx] = v, ne[idx] = h[u], f[idx] = c, w[idx] = d, h[u] = idx++;
    e[idx] = u, ne[idx] = h[v], f[idx] = 0, w[idx] = -d, h[v] = idx++;
}

bool spfa() {
    int tt = 0, hh = 0;
    memset(incf, 0, sizeof incf);
    memset(d, 0xcf, sizeof d);
    q[tt++] = S, d[S] = 0, incf[S] = INF;
    while (hh != tt) {
        int t = q[hh++];
        vis[t] = false;
        if (hh == N) hh = 0;
        for (int i = h[t]; ~i; i = ne[i]) {
            int j = e[i];
            if (f[i] && d[j] < d[t] + w[i]) {
                d[j] = d[t] + w[i];
                pre[j] = i;
                incf[j] = min(f[i], incf[t]);
                if (!vis[j]) {
                    vis[j] = true;
                    q[tt++] = j;
                    if (tt == N) tt = 0;
                }
            }
        }
    }
    return incf[T] > 0;
}

int EK() {
    int cost = 0;
    while (spfa()) {
        int t = incf[T];
        cost += d[T] * t;
        for (int i = T; i != S; i = e[pre[i] ^ 1]) 
            f[pre[i]] -= t, f[pre[i] ^ 1] += t; 
    }
    return cost;
}

void solve(int rule) {
    memset(h, -1, sizeof h), idx = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m + i - 1; j++) {
            insert(id[i][j] * 2, id[i][j] * 2 + 1, rule <= 1 ? 1 : INF, s[i][j]);
            if (i == 1) insert(S, id[i][j] * 2, 1, 0);
            if (i == n) insert(id[i][j] * 2 + 1, T, rule <= 1 ? 1 : INF, 0);
            if (i < n) {
                insert(id[i][j] * 2 + 1, id[i + 1][j] * 2, rule <= 2 ? 1 : INF, 0);
                insert(id[i][j] * 2 + 1, id[i + 1][j + 1] * 2, rule <= 2 ? 1 : INF, 0);
            }
        }
    }
    printf("%d\n", EK());
}

int main() {
    scanf("%d%d", &m, &n);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m + i - 1; j++) {
            scanf("%d", &s[i][j]);
            id[i][j] = ++cnt;
        }
    }
    S = 0, T = cnt * 2 + 2;
    
    for (int rule = 1; rule <= 3; rule++) solve(rule);
    return 0;
}

上一题