zoukankan      html  css  js  c++  java
  • [洛谷P3974] TJOI2015 组合数学

    问题描述

    为了提高智商,ZJY开始学习组合数学。某一天她解决了这样一个问题:给一个网格图,其中某些格子有财宝。每次从左上角出发,只能往右或下走。问至少要走几次才可能把财宝全捡完。

    但是她还不知足,想到了这个问题的一个变形:假设每个格子中有好多块财宝,而每一次经过一个格子至多只能捡走一块财宝,其他条件不变,至少要走几次才可能把财宝全捡完?

    这次她不会做了,你能帮帮她吗?

    输入格式

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

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

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

    输出格式

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

    样例输入

    1
    3 3
    0 1 5
    5 0 0
    1 0 0

    样例输出

    10

    数据范围

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

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

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

    解析

    不妨将每一个财宝都看作是一个点,那么所有财宝构成了一个DAG。问题就是求DAG的一个最小路径覆盖。接下来,我们需要一个结论:

    Dilworth定理:DAG的最小链覆盖=最大点独立集 最小链覆盖指选出最少的链(可以重复)使得每个点都在至少一条链中

    对于一个矩阵图(即使我们把每一个财宝都看成是点,这个图仍可以看做是矩阵图),最大独立集中的任意两个点一定可以构成左下—右上的关系。不妨考虑DP来解决这个问题。设(f[i][j])表示以点((i,j))为左下角的矩阵中的最大独立集大小。首先考虑继承关系,我们有

    [f[i][j]=max(f[i-1][j],f[i][j+1]) ]

    然后,我们有

    [f[i][j]=max(f[i][j],f[i-1][j+1]+a[i][j]) ]

    状态转移即可。

    代码

    #include <iostream>
    #include <cstdio>
    #define int long long
    #define N 1002
    using namespace std;
    int t,n,m,i,j,a[N][N],f[N][N];
    int read()
    {
    	char c=getchar();
    	int w=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c<='9'&&c>='0'){
    		w=w*10+c-'0';
    		c=getchar();
    	}
    	return w;
    }
    signed main()
    {
    	t=read();
    	while(t--){
    		n=read();m=read();
    		for(i=1;i<=n;i++){
    			for(j=1;j<=m;j++) a[i][j]=read();
    		}
    		for(i=1;i<=n;i++){
    			for(j=m;j>=1;j--){
    				f[i][j]=max(f[i][j+1],f[i-1][j]);
    				f[i][j]=max(f[i][j],f[i-1][j+1]+a[i][j]);
    			}
    		}
    		printf("%lld
    ",f[n][1]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    tp框架实现ajax
    tp框架的增删改查
    tp框架获取常量信息、方法、命名空间
    tp框架,访问方式、空方法
    tp基础,文件存储路径
    缓存
    CMS系统存储路径
    Smarty模版引擎的原理
    php的empty(),trim(),strlen()方法
    PHP 流程管理
  • 原文地址:https://www.cnblogs.com/LSlzf/p/12234925.html
Copyright © 2011-2022 走看看