這是壹種只有壹個棋子的遊戲。棋盤被分為N行,M列的方格,某個位置被標記為終點T。在任何壹個位置,棋子可以向左、右、上、下四個方向移動壹格,記移動距離為1。
在棋盤上有壹些特殊方格——飛行器,每個飛行器有壹個飛行距離d,棋子達到後可以繼續在同方向再“飛”d格,且移動距離仍然為1。例如,如果棋子在位置(2,8),飛行器在位置(2,7),且飛行距離為5,那麽棋子向左走壹格,將直接到達位置(2,2)且移動距離為1。如果飛行點落在棋盤外,則只能停在邊界上。例如,假若前個飛行器的飛行距離為10,那麽棋子的最終位置是(2,1)。
而且,如果飛行後的落點仍然是飛行器,則將連續飛行到目的地,且中間點不對當前棋子產生影響,當然也不算任何移動距離。例如,如果棋子位置在(2,8),飛行器在(2,7)、(2,5),且飛行距離都是5,此時棋子向左移動壹格,則(2,5)的飛行器將不產生作用,移動距離仍然為1。
妳的任務就是,編程計算出棋子達到終點的最短移動距離。
輸入:
輸入可以有多個測試用例。每個測試用例的第壹行是兩個整數N、M(3<=N, M<=100),表示棋盤的行列數。隨後是壹個整數K,表示飛行器的個數。接著的K行每行有3個正整數x、y、d,分別表示飛行器的位置(x,y)(2 <= x <= N-1, 2 <= y <= M-1)及飛行距離d。最後的兩行第壹行是棋子的初始位置S,第二行是終點位置T。妳可以假設數據總是合法的,S與T、飛行器位置互不相同。輸入0 0時表示結束
輸出:
每個測試用例輸出壹行,即達到終點的最短距離。如果不能達到,則輸出“Impossible”。
二、最少錢幣數:
(這個問題的輸入我感覺特別麻煩,希望給出比較好的輸入方法)
這是壹個古老而又經典的問題。用給定的幾種錢幣湊成某個錢數,壹般而言有多種方式。例如:給定了6種錢幣面值為2、5、10、20、50、100,用來湊15元,可以用5個2元、1個5元,或者3個5元,或者1個5元、1個10元,等等。顯然,最少需要2個錢幣才能湊成15元。
妳的任務就是,給定若幹個互不相同的錢幣面值,編程計算,最少需要多少個錢幣才能湊成某個給出的錢數。
輸入:
輸入可以有多個測試用例。每個測試用例的第壹行是待湊的錢數值M(1 <= M <= 2000,整數),接著的壹行中,第壹個整數K(1 <= K <= 10)表示幣種個數,隨後是K個互不相同的錢幣面值Ki(1 <= Ki <= 1000)。輸入M=0時結束。
輸出:
每個測試用例輸出壹行,即湊成錢數值M最少需要的錢幣個數。如果湊錢失敗,輸出“Impossible”。妳可以假設,每種待湊錢幣的數量是無限多的。
樣例輸入:
15
6 2 5 10 20 50 100
1
1 2
0
樣例輸出:
2
Impossible 最佳答案第壹題,典型的BFS找最短路
#include <iostream>
#define MAXN 105
using namespace std;
const int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int m,n;
int map[MAXN][MAXN];
int head,tail;
int queue[MAXN*MAXN][3];
bool hash[MAXN][MAXN];
int tx,ty;
int main()
{
while (cin>>n>>m && n>0)
{
int i,j,k;
memset(map,0,sizeof(map));
cin>>k;
while (k--)
{
cin>>i>>j;
i--;
j--;
cin>>map[i][j];
}
memset(hash,true,sizeof(hash));
cin>>queue[0][0]>>queue[0][1];
queue[0][0]--;
queue[0][1]--;
queue[0][2]=0;
hash[queue[0][0]][queue[0][1]]=false;
head=0;
tail=1;
cin>>tx>>ty;
tx--;
ty--;
while (head<tail && hash[tx][ty])
{
for (k=0;k<4;k++)
{
i=queue[head][0]+dir[k][0];
j=queue[head][1]+dir[k][1];
while (i>=0 && i<n && j>=0 && j<m && map[i][j]>0)
{
i+=map[i][j]*dir[k][0];
j+=map[i][j]*dir[k][1];
if (i<0 || i>=n || j<0 || j>=m)
{
if (i<0) i=0;
if (i>=n) i=n-1;
if (j<0) j=0;
if (j>=m) j=m-1;
break;
}
}
if (i>=0 && i<n && j>=0 && j<m)
if (hash[i][j])
{
queue[tail][0]=i;
queue[tail][1]=j;
queue[tail][2]=queue[head][2]+1;
hash[i][j]=false;
if (i==tx && j==ty) cout<<queue[tail][2]<<endl;
tail++;
}
}
head++;
}
if (hash[tx][ty]) cout<<"impossible"<<endl;
}
return 0;
}
第二題是典型的DP
用f[i][j]表示用前i種幣值湊出總額為j的錢所需的最少錢幣個數
狀態轉移方程f[i][j]=min{f[i-1][j](i>0時),f[i][j-Ki]+1(j>=Ki時),無窮大};
#include <iostream>
#define MAXM 2010
#definme MAXK 15
using namespace std;
int m,k;
int K[MAXK];
int f[MAXK][MAXM];
int main()
{
while (cin>>m && m>0)
{
int i,j;
cin>>k;
for (i=1;i<=k;i++) cin>>K[i];
memset(f,-1,sizeof(f));
f[0][0]=0;
for (i=1;i<=k;i++)
for (j=0;j<=m;j++)
{
int min;
min=-1;
if (f[i-1][j]!=-1 && (min==-1 || f[i-1][j]<min)) min=f[i-1][j];
if (j>=K[i] && f[i][j-K[i]]!=-1 && (min==-1 || f[i][j-K[i]]+1<min)) min=f[i][j-K[i]]+1;
f[i][j]=min;
}
if (f[k][m]==-1) cout<<"impossible"<<endl;
else cout<<f[k][m]<<endl;
}
return 0;
}