zoukankan      html  css  js  c++  java
  • 【洛谷3974】[TJOI2015] 组合数学(模拟最大流)

    点此看题面

    • 给定一张(n imes m)的网格图,格子((i,j))上有一个必须经过的次数(a_{i,j})
    • 一次只能从((1,1))向右或向下走到((n,m)),求至少需要走几次。
    • 数据组数(le2,n,mle10^3)

    模拟最大流

    模拟网络流什么的,说到底只是在给贪心找根据罢了。。。

    我们考虑按行枚举,那么肯定是尽可能让网络流向下而不是向右(因为我们本身就在向下,向下是必须的,而向右是不必要的)。

    我们用(f_{i,j})记录((i,j))保留的流量(具体实现中,由于我们一行一行枚举,第一维可以不要,也方便继承上行状态)。

    首先,每个位置都可以继承上一行对应位置的流量,如果这个流量小于这个位置上必需的流量,就需要从左边得到。

    所以我们从右往左枚举每一个位置,给每个位置打一个标记(b_{i,j}),表示它右边的点需要它提供的流量。

    因此,我们在让一个位置上的流量达到(a_{i,j})之后,还要尝试给它减去(b_{i,j})表示为右边提供,如果无法提供,同样需要从左边得到,类似地给左边的(b_{i,j-1})打上标记。

    而每一行第一个位置左边需要提供的流量,就是我们需要计入答案的贡献了。

    代码:(O(Tnm))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 1000
    #define LL long long
    using namespace std;
    int n,m;LL a[N+5][N+5],b[N+5][N+5],f[N+5];
    int main()
    {
    	RI Tt,i,j;LL ans;scanf("%d",&Tt);W(Tt--)
    	{
    		for(scanf("%d%d",&n,&m),i=1;i<=n;++i) for(j=1;j<=m;++j) scanf("%lld",&a[i][j]),f[j]=b[i][j]=0;
    		for(ans=0,i=1;i<=n;ans+=b[i++][0]) for(b[i][0]=0,j=m;j;--j)//统计每行最左边需要的流量
     			f[j]<a[i][j]&&(b[i][j-1]=a[i][j]-f[j],f[j]=a[i][j]),(f[j]-=b[i][j])<0&&(b[i][j-1]+=-f[j],f[j]=0);//流量首先需要达到a[i][j],然后需要提供给右边b[i][j]
    		printf("%lld
    ",ans);
    	}return 0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    ubuntu 14.04 下实现浏览器接收UDP视频流
    附加作业:黄金点游戏
    [福大软工] Z班 软件工程实践总结 作业成绩
    [福大软工] Z班——Beta现场答辩反馈
    [福大软工] Z班——个人技术博客评分
    [Gamma阶段]第十次Scrum Meeting
    [Gamma阶段]第九次Scrum Meeting
    [Gamma阶段]第八次Scrum Meeting
    [Gamma阶段]第七次Scrum Meeting
    [Gamma阶段]第六次Scrum Meeting
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3974.html
Copyright © 2011-2022 走看看