方格取数

Posted malcolmmeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了方格取数相关的知识,希望对你有一定的参考价值。

题目链接http://noi.openjudge.cn/ch0206/8786/

描述

设有N*N的方格图(N<=10),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下图所示(见样例):< p="">

技术分享图片

某人从图的左上角的A 点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。 此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。

 

输入输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。输出只需输出一个整数,表示2条路径上取得的最大的和。样例输入

8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21 
5 6 4
6 3 15
7 2 14
0 0 0

样例输出

67

来源NOIP2000复赛 提高组 第四题

(WA)原来想先取一次最优解,更新后,再去一次最优解。发现过不了。这是一种贪心,这两个局部最优解不一定是整体最优解。可能两个局部最优解不可能把整个带数的格子取完,但整体最优解可以。

(AC)   后来查了一下,发现这个是一个多线程DP,同时模拟两个人走。

       dp[i][j][k][r]表示第一个人走到(i,j),第二个人走到(k,r)的最优解。其可由max(dp[i-1][j][k-1][r],dp[i][j-1][k][r-1]),dp[i][j-1][k-1][r],max(dp[i-1][j][k][r-1]) + {maps[i][j](两个人位置重合时)或 maps[i][j]+maps[k][r](两个人位置不重合时)}转移而来。

WA:

技术分享图片
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#define DEBUG(x) cout<<#x<<" = "<<x<<endl
using namespace std;
int N;
int Matrix[15][15];
int Len[15][15];
void dfs(int i,int j,int l)
{
    if(l==0)return ;
    if(Len[i+1][j]>Len[i][j+1])dfs(i+1,j,l-Matrix[i][j]);
    else dfs(i,j+1,l-Matrix[i][j]);
    if(Len[i][j]==l&&Matrix[i][j]!=0){
            Matrix[i][j]=0;
    }
}
int main()
{
    scanf("%d",&N);
    int ans=0;
    while(true){
        int i,j,v;
        scanf("%d%d%d",&i,&j,&v);
        if(i==0)break;
        Matrix[i][j]=v;
    }
    Len[N][N]=Matrix[N][N];
    for(int k=N-1;k>=1 ;k-- ){
        Len[N][k]+=Len[N][k+1];
        Len[k][N]+=Len[k+1][N];
    }
    for(int i=N-1;i>=1 ;i-- ){
        for(int j=N-1;j>=1 ;j-- ){
            Len[i][j]=max(Len[i][j+1],Len[i+1][j])+Matrix[i][j];
        }
    }
    dfs(1,1,Len[1][1]);
    ans=Len[1][1];
    memset(Len,0,sizeof(Len));
    Len[N][N]=Matrix[N][N];
    for(int k=N-1;k>=1 ;k-- ){
        Len[N][k]+=Len[N][k+1];
        Len[k][N]+=Len[k+1][N];
    }
    for(int i=N-1;i>=1 ;i-- ){
        for(int j=N-1;j>=1 ;j-- ){
            Len[i][j]=max(Len[i][j+1],Len[i+1][j])+Matrix[i][j];
        }
    }
    ans+=Len[1][1];
    printf("%d
",ans);

}
View Code

AC:

技术分享图片
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#define DEBUG(x) cout<<#x<<" = "<<x<<endl
int N;
int Matrix[15][15];
int maxLen[15][15][15][15];
using namespace std;
int main()
{
//    freopen("in.txt","r",stdin);
    scanf("%d",&N);
    while(true){
        int i,j,v;
        scanf("%d%d%d",&i,&j,&v);
        if(i==0)break;
        Matrix[i][j]=v;
    }
    maxLen[1][1][1][1]=Matrix[1][1];
    for(int i=1;i<=N ;i++ ){
        for(int j=1;j<=N ;j++ ){
                for(int l=1;l<=N ;l++ ){
                    for(int m=1;m<=N ;m++ ){
                        int p1=max(maxLen[i-1][j][l-1][m],maxLen[i][j-1][l][m-1]);
                        int p2=max(maxLen[i][j-1][l-1][m],maxLen[i-1][j][l][m-1]);
                        int r=max(p1,p2);
                        if(i==l&&j==m)maxLen[i][j][l][m]=r+Matrix[i][j];
                        else {
                            maxLen[i][j][l][m]=r+Matrix[i][j]+Matrix[l][m];
                        }
                    }
                }
        }
    }
    printf("%d
",maxLen[N][N][N][N]);
}
View Code

还有一个问题比较迷,为什么是从这四个状态转移过来的dp[i-1][j][k-1][r],dp[i][j-1][k][r-1]),dp[i][j-1][k-1][r],max(dp[i-1][j][k][r-1]?

参考文献

https://blog.csdn.net/heyanbai/article/details/79519532

以上是关于方格取数的主要内容,如果未能解决你的问题,请参考以下文章

方格取数问题

「网络流 24 题」方格取数

DP洛谷1004方格取数

HDU 1565 1569 方格取数(最大点权独立集)

HDU 1565 方格取数

方格取数问题 最小割