• P4850 [IOI2009]葡萄干raisins 记忆化搜索


    $ color{#0066ff}{ 题目描述 }$

    普罗夫迪夫的著名巧克力大师Bonny需要切开一板带有葡萄干的巧克力。巧克力是一个包含许多相同的方形小块的矩形。小块沿着巧克力的边排列成n行m列,即共有nm块。每个小块上有1个或多个葡萄干,没有葡萄干在小块的边上或者跨过两个小块。 最开始,巧克力是一整块。Bonny需要把它切成上述的nm个独立的小块。因为Bonny很忙,她需要她的助手Sly peter帮她切。Peter只能从一端到另一端切直线并且他要为他的每一刀得到报酬。Bonny手头没有钱,但是她有足够的葡萄干,所以她提出用葡萄干付给peter。Sly peter同意接受葡萄干,但是有下面的条件:每次他把给定的一块巧克力切成两小块,他都要得到和那块给定的巧克力上葡萄干数目相同的葡萄干。 Bonny想要付给peter尽可能少的葡萄干。她知道这nm个小块中每一个小块上葡萄干的数目。她可以选择递给peter的巧克力的顺序,也可以告诉peter如何切(横切还是竖切)以及从哪里切。请告诉Bonny如何把巧克力切成一个个独立的小块。使她能够付给Sly peter尽可能少的葡萄干。

    任务 写一个程序,给定每个小块上葡萄干的数目,计算Bonny要付给Sly peter的最少的葡萄干的数目。

    (color{#0066ff}{输入格式})

    你的程序必须从标准输入中读取下列数据:
    第一行包含整数n和m,以一个空格隔开。
    接下来的n行描述了每个小块上葡萄干的数目。这n行中第kth行描述的是第kth行小块巧克力。每行包含m个整数,分别以一个空格隔开。这些整数描述的是该行从左到右的小块。第kth行的第pth个整数表示位于第kth行第pth列的小块上的葡萄干数目。

    (color{#0066ff}{输出格式})

    你的程序必须向标准输出写入一行,该行包含一个整数;Bonny要付给Sly peter的最少的葡萄干的数目。

    评分规则 有25分的评测数据,n,m<=7。

    (color{#0066ff}{输入样例})

    2 3
    2 7 5
    1 9 5	
    

    (color{#0066ff}{输出样例})

    77
    

    (color{#0066ff}{数据范围与提示})

    1<=n,m<=50 巧克力两条边上小块的数目
    1<=k,p<=1,000 第kth行第pth列的小块上的葡萄干数目

    (color{#0066ff}{题解})

    一看这题,先搜索暴力有25pts,然后发现可以记忆化,然后。。。就A了。。这。。。

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    template<class T> bool chkmax(T &a, const T &b) { return a < b? a = b, 1 : 0; }
    template<class T> bool chkmin(T &a, const T &b) { return b < a? a = b, 1 : 0; }
    const int inf = 0x7fffffff;
    const int maxn = 1050;
    int n, m;
    int s[maxn][maxn], f[55][55][55][55];
    int getsum(int x, int y, int xx, int yy) {
    	return s[xx][yy] - s[x - 1][yy] - s[xx][y - 1] + s[x - 1][y - 1];
    }
    int work(int x, int y, int xx, int yy) {
    	if(f[x][y][xx][yy]) return f[x][y][xx][yy];
    	if(x == xx && y == yy) return 0;
    	int ans = inf;
    	for(int i = x; i < xx; i++) chkmin(ans, work(x, y, i, yy) + work(i + 1, y, xx, yy));
    	for(int i = y; i < yy; i++) chkmin(ans, work(x, y, xx, i) + work(x, i + 1, xx, yy));
    	return f[x][y][xx][yy] = ans + getsum(x, y, xx, yy);
    }
    int main() {
    	n = in(), m = in();
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= m; j++)
    			s[i][j] = s[i][j - 1] + s[i - 1][j] - s[i - 1][j - 1] + in();
    	printf("%d
    ", work(1, 1, n, m));
    	return 0;
    }
    
  • 相关阅读:
    TSQL 错误状态
    CSS光标聚焦改指针为手
    PD使用指导
    Ext 为label添加单击事件
    (转) SQL Server中解决死锁的新方法介绍
    DateTime 的使用技巧
    (转) C# 接口
    常见频率f与周期T之间的关系
    上拉电阻与下拉电阻的作用和区别
    powershell命令返回值
  • 原文地址:https://www.cnblogs.com/olinr/p/10685427.html
Copyright © 2020-2023  润新知