组合数学 TJOI2015DAY1_T2

版权声明:神犇使用记得标明出处哦QAQ https://blog.csdn.net/qq_41717018/article/details/83386792

组合数学(math)

时间限制: 2 Sec  内存限制: 128 MB

题目描述

为了提高智商,zjy开始学习组合数学。某一天她解决了这样一个问题:“给一个网格图,其中某些格子有财宝。每次从左上角出发,只能往右或下走。问至少要走几次才能把财宝全部捡完。”但是她还不知足,想到了这个问题的一个变形:假设每个格子中有好多块财宝,而每一次经过一个格子至多只能捡到一块财宝,其他条件不变,至少要走几次才可能把财宝全捡完?

 

 

输入

第一行为一个正整数t,表示数据组数。

每组数据的第一行是两个正整数n和m,表示这个网格图有n行m列。

接下来n行,每行m个非负整数,表示这个格子中的财宝数量(0表示没有财宝)。

 

输出

对于每组数据,输出一个整数,表示至少走的次数。

 

提示

【数据规模】

对于30%的数据,n<=5,m<=5,每个格子中的财宝数不超过5块

对于50%的数据,n<=100,m<=100,每个格子中的财宝数不超过1000块。

对于100%的数据,n<=1000,m<=1000,每个格子的财宝数不超过10^6块。

题解:

可以看看这篇博客:https://www.cnblogs.com/Konjakmoyu/p/6680997.html

我大概yy了一下:

最开始,想到可能可以有个网络流,跑一遍类似有流量下界的最小流的东西。

然后看看数据范围。。。

假设有两个点无法互相依照题中方法相互到达。

那么,对于答案来说,至少是有两条路径要通过这两个点才会走完。

于是,考虑有一条链,链上两个点两两互相不可到达,并且路径都是经过这条链上的每个点。

这条链就叫做反链。

有个Dilworth定理:最少链数=最大权值反链的权值

这题相当于就是用最小的最大值为1的链,用最小条数覆盖这张图。、

然后就DP出最长反链即可。

证明挖坑待补。

#include<bits/stdc++.h>
using namespace std;
#define in inline
#define re register
#define rep(i,a,b) for(re int i=a;i<=b;i++)
#define repd(i,a,b) for(re int i=a;i>=b;i--)
#define For(i,a,b) for(int i=a;i<b;i++)
#define _(d) while(d(isdigit(ch=getchar())))
template<class T>in void g(T&t){T x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;t=f*x;}
const int N=1004;
int a[N][N],f[N][N],n,m;
int main(){
	//freopen(".in","r",stdin);freopen(".out","w",stdout);
	int T;g(T);
	while(T--){
		g(n),g(m);
		rep(i,1,n) rep(j,1,m) g(f[i][j]);
		rep(j,1,m){
			repd(i,n,1){
				f[i][j]=max(f[i][j]+f[i+1][j-1],max(f[i+1][j],f[i][j-1]))+a[i][j];
			}
		}
		cout<<f[1][n]<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41717018/article/details/83386792
今日推荐