1. 程式人生 > >演算法訓練 方格取數 藍橋杯

演算法訓練 方格取數 藍橋杯

問題描述
  設有N*N的方格圖(N<=10),我們將其中的某些方格中填入正整數,而其他的方格中則放入數字0。
  某人從圖的左上角的A 點(1,1)出發,可以向下行走,也可以向右走,直到到達右下角的B點(N,N)。在走過的路上,他可以取走方格中的數(取走後的方格中將變為數字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

思路

一個人走兩次可以看做兩個人同時走,這裡有兩個要點:

x1+y1=x2+y2 也就是說這兩人並排在一條斜線

為了和最大,兩人除了開頭結尾,不能走過同一個格子上

藍橋oj最後一個測試資料貌似有問題;錦囊裡的那個遞推式不符合最優子結構,因為F(i-1,j,k'')不是最大,但是兩個V值足夠大,也能得到最優解

#include<stdio.h>
#define max2(a,b) a>b?a:b
#define min2(a,b) a<b?a:b
int a[100][100]={0};//儲存表格
int N;
int main(){
int x,y,i,j,k,q,t,max,min,x1,x2;
int dp[20][20][20][20]={0};//儲存從兩點到終點的路徑經過的數值和的最大值
int yb[2],yc[2],xb[2],xc[2];
scanf("%d",&N);
while(1){
    scanf("%d%d",&x,&y);
    scanf("%d",&a[x][y]);
    if(x==0&&y==0&&a[x][y]==0)
        break;
}
dp[N][N][N][N]=a[N][N];
for(i=2*N-1;i>=2;i--){//兩點總在同一直線上,i=x+y,把表格看作一條一條斜線
    max=min2(N,i-1);
    min=max2(1,i-N);
    for(x1=min;x1<=max;x1++){
        for(x2=min;x2<=max;x2++){//遍歷在這條斜線上,兩個點的任意組合
            if(x1==x2&&!(x1==1&&x2==1))continue;
            yb[0]=i-x1+1;
            yb[1]=i-x1;
            xb[0]=x1;
            xb[1]=x1+1;
            yc[0]=i-x2+1;
            yc[1]=i-x2;
            xc[0]=x2;
            xc[1]=x2+1;
            q=0;
            for(j=0;j<=1;j++){
                for(k=0;k<=1;k++){
                if(xb[j]==xc[k])continue;//同一直線,x不同,就不會重疊
                if(q<(t=a[x1][i-x1]+a[x2][i-x2]+dp[xb[j]][yb[j]][xc[k]][yc[k]])){
                   q=t;
                   }
                }
            }
        dp[x1][i-x1][x2][i-x2]=q;
        }
    }
}
dp[1][1][1][1]-=a[1][1];
printf("%d",dp[1][1][1][1]);
return 0;
}