zoukankan      html  css  js  c++  java
  • 动态规划--lgP1004 方格取数,P1006 传纸条

    1.方格取数:找到两条路线使得获得的总价值最大

    定义状态:f[i][j][l][k]表示第一个路线走到(i,j),第二个路线走到(l,k)的最大价值

    状态转移:和数字三角形一样f[i][j][l][k]=max(max(f[i][j-1][l][k-1],f[i-1][j][l][k-1]),max(f[i][j-1][l-1][k],f[i-1][j][l-1][k]))+a[i][j]+a[l][k];

    但是题目规定取完的数会变成0,所以当(i,j)和(l,k)是同一个位置时要减去一个a[i][j]

    代码:

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <cstring>
     5 using namespace std;
     6 int x,y,w,n;
     7 const int maxn=10;
     8 int a[maxn][maxn],f[maxn][maxn][maxn][maxn];
     9 int main(){
    10     scanf ("%d",&n);
    11     while (scanf ("%d%d%d",&x,&y,&w)&&x!=0&&y!=0&&w!=0){
    12         a[x][y]=w;
    13     }
    14     for (int i = 1;i <= n;i++){
    15         for (int j = 1;j <= n;j++){
    16             for (int l = 1;l <= n;l++){
    17                 for (int k = 0;k <= n;k++){
    18                     f[i][j][l][k]=max(max(f[i][j-1][l][k-1],f[i-1][j][l][k-1]),max(f[i][j-1][l-1][k],f[i-1][j][l-1][k]))+a[i][j]+a[l][k];
    19                     if (i==l&&j==k) f[i][j][l][k]-=a[i][j];
    20                 }
    21             }
    22         }
    23     }
    24     cout<<f[n][n][n][n]<<endl;
    25 }

    2.传纸条

    和上一道题一毛一样嗷,惟一的区别是,上一道题去过的数还是可以走,只是没贡献,但是这一道题是取过的就不能走了,但是本质是相同的,那就在这里证明一下。

    动态规划都知道是从一个状态转移到另一个状态,如果现在(i,j)和(l,k)是同一个位置,那么一个的贡献为0,当前位置f[i][j][l][k]=f[i-1][j][l-1][k]|f[i-1][j][l][k-1]|f[i][j-1][l][k-1]|f[i][j-1][l-1][k];如果换个方向走,且这个方向没走过,那么就f[i][j][l][k]=f[i-1][j][l-1][k]|f[i-1][j][l][k-1]|f[i][j-1][l][k-1]|f[i][j-1][l-1][k]加上一个数一定>本身,max自动忽略另一个贡献为0的方案。如果另一个方向贡献还为0,我们在跳回上上一个点,如果他往(i,j)这个方向走,那么贡献一定为0,所以需要往另一个方向走才能加贡献,如果还是为0,继续向上走,总会有一个方向的贡献不为0.所以每次我们在取max的时候,会自动忽略已经走过的路线。

    代码:

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <cstring>
     5 using namespace std;
     6 int x,y,w,n,m,mark,x1,x2,y1,y2;
     7 const int maxn=55;
     8 int a[maxn][maxn],f[maxn][maxn][maxn][maxn];
     9 int main(){
    10     scanf ("%d%d",&n,&m);
    11     for (int i = 1;i <= n;i++){
    12         for (int j = 1;j <= m;j++){
    13             scanf ("%d",&a[i][j]);
    14             if (a[i][j]==0&&mark==0) {x1=i,y1=j;mark++;}
    15             if (a[i][j]==0&&mark!=0) x2=i,y2=j; 
    16         }
    17     }
    18     for (int i = x1;i <= x2;i++){
    19         for (int j = y1;j <= y2;j++){
    20             for (int l = x1;l <= x2;l++){
    21                 for (int k = y1;k <= y2;k++){
    22                     f[i][j][l][k]=max(max(f[i][j-1][l][k-1],f[i-1][j][l][k-1]),max(f[i][j-1][l-1][k],f[i-1][j][l-1][k]))+a[i][j]+a[l][k];
    23                     if (i==l&&j==k) f[i][j][l][k]-=a[i][j];
    24                 }
    25             }
    26         }
    27     }
    28     cout<<f[x2][y2][x2][y2]<<endl;
    29 }
  • 相关阅读:
    UOJ299 游戏
    SPOJ-DivCnt2 Counting Divisors (square)
    Gym102331B Bitwise Xor
    POJ3495 Bitwise XOR of Arithmetic Progression
    LG5325 【模板】Min_25筛
    LOJ6229 这是一道简单的数学题
    BZOJ3601 一个人的数论
    LOJ138 类欧几里得算法
    Atcoder TypicalDPContest N~T
    莫队基础题
  • 原文地址:https://www.cnblogs.com/very-beginning/p/13546255.html
Copyright © 2011-2022 走看看