求编程大赛冠军

一、象棋比赛:

这是一个只有一个棋子的游戏。棋盘分为n行m列,某个位置标记为终点t,在任意位置,棋子可以左右上下移动一格,移动距离为1。

棋盘上有一些特殊的方格——飞机。每架飞机都有一个飞行距离D,棋子到达后可以继续同方向“飞”D方块,移动距离仍为1。比如棋子在(2,8)位置,飞机在(2,7)位置,飞行距离为5,那么棋子会直接走到(2,2)位置,移动距离为1。如果飞点落在棋盘外,只能停在边界。比如前一架飞机的飞行距离是10,那么棋子的最终位置就是(21)。

而且如果飞行后的落点仍然是飞行器,那么它会继续飞向目的地,中间点不会影响当前棋子,当然也不会算作任何移动距离。比如棋子在(2,8),飞机在(2,7)和(2,5),飞行距离是5,那么棋子向左移动一格,那么(2,5)的飞机就不起作用,移动距离还是1。

你的任务是编程并计算棋子到达终点的最短移动距离。

输入:

输入可以有多个测试用例。每个测试用例的第一行是两个整数n,m (3

输出:

每个测试用例输出一行,即到终点的最短距离。如果无法实现,则输出“不可能”。

二、最小硬币数:

这个问题输入起来感觉特别麻烦,希望能给出更好的输入法。

这是一个古老而经典的问题。一般来说,有很多方法可以用给定数量的硬币赚到一定数量的钱。例如,给定面额为2、5、10、20、50、100的六种硬币,要凑成1 5元,可以用五个2元,1 5元,或者三个5元,或者15元,15元。显然,至少需要2个硬币才能凑足15元。

你的任务是给出一些不同面值的硬币,编程并计算出至少需要多少硬币才能组成给定的金额。

输入:

输入可以有多个测试用例。每个测试用例的第一行是货币值m (1

输出:

每个测试用例输出一行,即组成货币值m所需的最小硬币数,如果收集失败,输出“不可能”。你可以假设要收集的每个硬币的数量是无限的。

样本输入:

15

6 2 5 10 20 50 100

1

1 2

样本输出:

2

不可能第一个问题的最佳答案是,典型的BFS会找到最短的路径。

# include & ltiostream & gt

#定义MAXN 105

使用命名空间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];

布尔哈希[MAXN][MAXN];

int tx,ty;

int main()

{

而(CIN & gt;& gtn & gt& gtm & amp& ampn & gt0)

{

int i,j,k;

memset(map,0,sizeof(map));

CIN & gt;& gtk;

while (k -)

{

CIN & gt;& gt我& gt& gtj;

I-;

j-;

CIN & gt;& gtmap[I][j];

}

memset(hash,true,sizeof(hash));

CIN & gt;& gt队列[0][0]& gt;& gt队列[0][1];

队列[0][0]-;

队列[0][1]-;

队列[0][2]= 0;

hash[queue[0][0]][queue[0][1]]= false;

head = 0;

tail = 1;

CIN & gt;& gttx & gt& gtty;

tx-;

ty-;

while(head & lt;尾巴& amp& amp哈希[tx][ty])

{

for(k = 0;k & lt4;k++)

{

I =队列[头][0]+目录[k][0];

j =队列[head][1]+dir[k][1];

while(I & gt;= 0 & amp& amp我& ltn & amp& ampj & gt= 0 & amp& ampj & ltm & amp& ampmap[I][j]& gt;0)

{

I+= map[I][j]* dir[k][0];

j+= map[I][j]* dir[k][1];

如果(我& lt0 | | i & gt= n | | j & lt0 | | j & gt=m)

{

如果(我& lt0)I = 0;

如果(i & gt= n)I = n-1;

if(j & lt;0)j = 0;

if(j & gt;= m)j = m-1;

打破;

}

}

如果(i & gt= 0 & amp& amp我& ltn & amp& ampj & gt= 0 & amp& ampj & ltm)

if(哈希[i][j])

{

queue[tail][0]= I;

queue[tail][1]= j;

queue[tail][2]= queue[head][2]+1;

hash[I][j]= false;

if(I = = tx & amp;& ampj = = ty)cout & lt;& ltqueue[tail][2]& lt;& ltendl

tail++;

}

}

head++;

}

if(hash[tx][ty])cout & lt;& lt“不可能”& lt& ltendl

}

返回0;

}

第二个问题是典型的DP。

F[i][j]表示用前I种货币的总数J来凑整货币所需的最少硬币数。

状态转移方程f[I][j]= min { f[I-1][j](I >;0),f[I][j-Ki]+1(j & gt;=Ki),infinity };

# include & ltiostream & gt

#定义MAXM 2010

# define me MAXK 15

使用命名空间std

int m,k;

int K[MAXK];

int f[MAXK][MAXM];

int main()

{

而(CIN & gt;& gtm & amp& ampm & gt0)

{

int i,j;

CIN & gt;& gtk;

for(I = 1;我& lt= k;i++)CIN & gt;& gtk[I];

memset(f,-1,sizeof(f));

f[0][0]= 0;

for(I = 1;我& lt= k;i++)

for(j = 0;j & lt= m;j++)

{

int min

min =-1;

if (f[i-1][j]!=-1 & amp;& amp(min = =-1 | | f[I-1][j]& lt;min))min = f[I-1][j];

if(j & gt;= K[I]& amp;& ampf[i][j-K[i]]!=-1 & amp;& amp(min = =-1 | | f[I][j-K[I]]+1 & lt;min))min = f[I][j-K[I]]+1;

f[I][j]= min;

}

if(f[k][m]= =-1)cout & lt;& lt“不可能”& lt& ltendl

else cout & lt& ltf[k][m]& lt;& ltendl

}

返回0;

}