数字梯形问题

梯形的第一行有 mm 个数字。从梯形的顶部的 mm 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径。

分别遵守以下规则:

1.从梯形的顶至底的 mm 条路径互不相交;

2.从梯形的顶至底的 mm 条路径仅在数字结点处相交;

3.从梯形的顶至底的 mm 条路径允许在数字结点相交或边相交。

将按照规则 1 ,规则 2 ,和规则 3 计算出的最大数字总和并输出,每行一个最大总和。

嗯不难,有点麻烦。
规则1:化点为边,把一个点拆成两个边,然后加一条容量为1,费用为点权的有向边,然后对于下一层的加一个容量1,费用0的边,跑最大费用最大流即可。
规则2:直接建图,把到下一层的边的容量设为1,然后把费用为上层点的权值,最大费用最大流
规则3:除了把上下两层的容量改为inf意外不做修改,最大费用最大流即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int S=0,T=100003,inf=0x3f3f3f3f;
int m,n,tmd;
int g[25][55],id[55][55],ecnt=1,head[1000005],from[1000005],dis[1000005];
bool inq[10005];
struct Edge {
    int to,nxt,val,cost,from;
} e[1000010];
void add(int bg,int ed,int val,int cost) {
    e[++ecnt].cost=cost;
    e[ecnt].from=bg;
    e[ecnt].nxt=head[bg];
    e[ecnt].to=ed;
    e[ecnt].val=val;
    head[bg]=ecnt;
}
void insert(int bg,int ed,int val,int cost) {
    add(bg,ed,val,cost);
    add(ed,bg,0,-cost);
}
queue<int>q;
bool spfa() {
    q.push(S);
    std::memset(dis,0x3f,sizeof dis);
    std::memset(inq,0,sizeof inq);
    dis[S]=0;
    inq[S]=1;
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        inq[u]=0;
        for(int i=head[u],v; i; i=e[i].nxt) {
            v=e[i].to;
            if(dis[v]>dis[u]+e[i].cost&&e[i].val) {
                dis[v]=dis[u]+e[i].cost;
                from[v]=i;
                if(!inq[v]) q.push(v),inq[v]=1;
            }
        }
    }
    return dis[T]!=inf;
}
void min(int &x,int y) {x=x<y?x:y;}
int mincost;
void mcf() {
    int x=inf,i=from[T];
    while(i) {min(x,e[i].val);i=from[e[i].from];}
    i=from[T];
    while(i) {
        e[i].val-=x;
        e[i^1].val+=x;
        mincost+=x*e[i].cost;
        i=from[e[i].from];
    }
}
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",&g[i][j]),id[i][j]=++tmd;
    for(int i=1; i<=m; i++)
        insert(S,i,1,0);
    for(int i=1; i<n; i++) 
        for(int j=1; j<=m+i-1; j++) 
            insert(id[i][j],id[i][j]+tmd,1,-g[i][j]),insert(id[i][j]+tmd,id[i+1][j],1,0),insert(id[i][j]+tmd,id[i+1][j+1],1,0); 
    for(int j=1;j<=n+m-1;j++) insert(id[n][j],id[n][j]+tmd,1,-g[n][j]);
    for(int i=1; i<=n+m; i++) insert(id[n][i]+tmd,T,1,0);
    while(spfa())mcf();
    cout<<-mincost<<endl;
    memset(head,0,sizeof head),ecnt=1;
    mincost=0;
    for(int i=1;i<n;i++) 
        for(int j=1;j<=m+i-1;j++)
            insert(id[i][j],id[i+1][j],1,-g[i][j]),insert(id[i][j],id[i+1][j+1],1,-g[i][j]);
    for(int i=1;i<=m;i++) insert(S,i,1,0);
    for(int i=1;i<=n+m-1;i++) insert(id[n][i],T,inf,-g[n][i]);
    while(spfa())mcf();
    cout<<-mincost<<endl;
    memset(head,0,sizeof head),ecnt=1;
    mincost=0;
    for(int i=1;i<n;i++) 
        for(int j=1;j<=m+i-1;j++)
            insert(id[i][j],id[i+1][j],inf,-g[i][j]),insert(id[i][j],id[i+1][j+1],inf,-g[i][j]);
    for(int i=1;i<=m;i++) insert(S,i,1,0);
    for(int i=1;i<=n+m-1;i++) insert(id[n][i],T,inf,-g[n][i]);
    while(spfa())mcf();
    cout<<-mincost<<endl;
}

猜你喜欢

转载自www.cnblogs.com/sdfzhsz/p/9271482.html