BZOJ 3997 [TJOI2015]组合数学

最大点独立集+DP

答案就是在图中选出一些点,使得两两不可达且权值和最大。

然而并没有找到证明,于是只好自己脑补。大概是会证(口)明(胡)了吧……现给出我的证明如下:

先分析出行进的策略:走到第一行最右的一个非零格子,向下走一行进入第二行,走到右边最右的一个非零格子(若无则不走),向下走一行进入第三行,走到右边最右的一个非零格子(若无则不走) ……走到右下角。

证明:易知选出的点集中最右上的(称作x)那个一定在第一遍的行进路上。只需证明当x的权值减完之后,点集S中除x以外的最右上的点(称作y)在接下来的行进路上,即可说明存在这样一种方案。

首先,显然x,y围成的矩形内(不含边界)中不可能有点,否则加入点集更优。假设y无法进入当前行进路,即y的右上角还有点,设为u。易知这个点不会在x的右上方,否则就不会轮到x。这个点只能在[y的右上]与[x的左上或右下] 的交集之中。此时用u替换x,点集S权值更优。但可能导致u和x的前一个点集中的右上的点无法衔接,即变得可达。设x的前一个点集中的右上点为z。如果z一直都在消u,则把z也丢掉即可。如果z消u之前在消v(即v,u不可达,v不属于点集S),则用v,u共同替换x,z答案更优,此时继续递归寻找z的右上点,变成子问题。点集S中最右上的点没有右上点,因此子问题可以结束,即可以找到最优解。

可能你看不懂我在说什么,建议把图画出来比一比,那样应该就知道了QAQ

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1005 
using namespace std;
namespace runzhe2000
{
    int f[N][N], a[N][N];
    void main()
    {
        int T; 
        scanf("%d",&T);
        for(; T--;)
        {
            int n, m;
            scanf("%d%d",&n,&m); memset(f,0,sizeof f);
            for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) scanf("%d",&a[i][j]);
            for(int i = 1; i <= n; i++) for(int j = m; j >= 1; j--) f[i][j] = max(a[i][j] + f[i-1][j+1], max(f[i-1][j], f[i][j+1]));
            printf("%d\n",f[n][1]);
        }
    }
}
int main()
{
    runzhe2000::main();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值