• 数字梯形问题


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

    分别遵守以下规则:

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

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

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

    将按照规则 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;
    }
    
    我是咸鱼。转载博客请征得博主同意Orz
  • 相关阅读:
    cstc2018 混合果汁
    CF1086E Beautiful Matrix
    AT2000 Leftmost Ball
    CF1208E Let Them Slide
    CF1208D Restore Permutation
    【置顶】博客公告
    [NOI2015]软件包管理器
    【noip2018】积木大赛
    几天连测总结
    【ZJOI2007】棋盘制作
  • 原文地址:https://www.cnblogs.com/sdfzhsz/p/9271482.html
Copyright © 2020-2023  润新知