演算法訓練 方格取數 藍橋杯
阿新 • • 發佈:2019-02-04
問題描述
設有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
設有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; }