《挑战程序设计竞赛》 一二章部分代码题解

最近在看这本书,由于我在网上没有找到代码,特地把我的代码贴出来以供参考。由于是手敲,与书上的有所不同,如有错误欢迎指教。

1.6.2 POJ 1852

本题关键在于理解两只蚂蚁相遇后相当于交错而过继续前行。

 1 #include <cstdio>
 2 #include <iostream>
 3 //#include <algorithm>
 4 #define max(a,b) ((a)>(b)?(a):(b))
 5 #define min(a,b) ((a)<(b)?(a):(b))
 6 using namespace std;
 7 int main(void)
 8 {
 9     int num;
10     int length, n;
11     scanf("%d",&num);
12     for(int i=0; i<num; i++)
13   {
14     scanf("%d%d",&length,&n);
15     int ma=0, mi=0;
16     int temp;
17     for(int j=0; j<n; j++)
18     {
19       scanf("%d",&temp);
20       mi = max(mi, min(temp, length-temp));
21       ma = max(ma, max(temp, length-temp));
22     }
23     printf("%d %d\n",mi, ma);
24   }
25     return 0;
26 }

 

 

2.1 搜索

2.1.4 POJ 2386

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int vis[105][105];//记忆数组 
char s[105][105];
int sum;
int n, m;
void dfs(int x, int y)
{
  if(vis[x][y]==1 || x<0 || x>=n || y<0 || y>=m || s[x][y]=='.')  return;
  vis[x][y] = 1;
  dfs(x-1, y-1);  dfs(x-1, y);  dfs(x-1, y+1);
  dfs(x, y-1);                  dfs(x, y+1);
  dfs(x+1, y-1);  dfs(x+1, y);  dfs(x+1, y+1);//向八个方向搜索 
}
int main(void)
{
    //freopen("2386.in","r",stdin);
    scanf("%d%d",&n,&m);
    sum = 0;
    getchar();//吃掉'\n' 
    for(int i=0; i<n; i++)
    for(int j=0; j<=m; j++)//多一个字符吃掉'\n' 
    {
      scanf("%c",&s[i][j]);
    }
  for(int i=0; i<n; i++)
    for(int j=0; j<m; j++)
    {
      if(vis[i][j]==0 && s[i][j]=='W')//有未搜索过的积水点 
      {
        sum++;
        dfs(i, j);
      }
    }
  printf("%d\n",sum);
    return 0;
}

 

2.1.5迷宫最短路径(bfs)

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <queue>
 6 using namespace std;
 7 #define INF 6666666
 8 typedef pair<int, int>  P;
 9 int n, m;
10 char maze[105][105];
11 int d[105][105];//起点到所有点的最少步数 
12 int dx[4]={1,0,-1,0}, dy[4]={0,1,0,-1};
13 int sx, sy, gx, gy;
14 queue<P>  que;
15 void bfs()
16 {
17   while(que.size())
18   {
19     P p = que.front(); que.pop();
20     if(p.first==gx && p.second==gy)  break;//队列第一个是已经被计算出来的 
21     for(int i=0; i<4; i++)
22     {
23       int nx = p.first + dx[i];
24       int ny = p.second + dy[i];//四个方向走 
25       if(nx>=0 && nx<n && ny>=0 && ny<m && maze[nx][ny]!='#' && d[nx][ny]==INF)
26       {
27         que.push(P(nx,ny));//如果可以走,则该点入队列 
28         d[nx][ny] = d[p.first][p.second] + 1;//求得该点最短步数 
29       }
30     }
31   }
32 }
33 int main(void)
34 {
35     //freopen("2-1-5.in","r",stdin);
36     scanf("%d%d",&n,&m);
37     for(int i=0; i<n; i++)
38     for(int j=0; j<=m; j++)
39     {
40       scanf("%c",&maze[i][j]);
41       d[i][j] = INF;
42       if(maze[i][j] == 'S')   { sx = i; sy = j; }//起点 
43       if(maze[i][j] == 'G')   { gx = i; gy = j; }//终点 
44     }
45   d[sx][sy] = 0;
46   que.push(P(sx, sy));//起点入队列 
47   bfs();
48   printf("%d",d[gx][gy]);
49     return 0;
50 }//2015-08-03 

2.2 贪心

2.2.3字典序最小问题(POJ3617)

本题关键在于利用正反串的比较来决定选择头字母还是尾字母,另外注意80字符换行。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
char s[2005], s0[2005], t[2005];
int n, b=0, g=0, b0=0, g0=0, u=0;
char c;
bool jud(void)
{
  for(int i=0; i<n; i++)
  {
    if(s[b+i]!=s0[b0+i]) return (s[b+i]<=s0[b0+i]);
  }
}//用于比较正串和反串来求最优解 
int main(void)
{
    //freopen("3617.in","r",stdin);
    scanf("%d",&n);
    for(int i=0; i<n; 1)
  {
    c = getchar();
    if(c>='A' && c<='Z')
    {
      s[i++] = c;
    }
  }
  for(int i=0; i<n; i++)
  {
    s0[i] = s[n-1-i];
  }//s0为s的反串 
  g=g0=n-1;
  while(b <= g)
  {
    if(jud()==1)  {t[u++]=s[b++];  g0--;}//取第一个字母 
    else  {t[u++]=s[g];    g--;  b0++;}//取最后一个字母 
  }
  for(int i=0; i<n; i++)
  {
      putchar(t[i]);
      if((i+1)%80 == 0)        putchar('\n');
  }    //输出每80字符换行 
  if((n+1)%80 != 0)
      putchar('\n');
    return 0;
}//2015-08-03 

 2.2.4

1. POJ 3069

本题关键在于找到一个点r范围内的最后一个点和那个点r范围外的第一个点。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int a[1005];
int n, r;
int main(void)
{
    //freopen("3069.in","r",stdin);
    while(scanf("%d%d",&r,&n))
  {
    int sum=0;
    if(n==-1 && r==-1)
      return 0;
    for(int i=0; i<n; i++)
    {
      scanf("%d",&a[i]);//输入每个点的位置 
    }
    sort(a, a+n);
    int i=0;
    while(i < n)
    {
      int s = a[i++];//从s点开始 
      while(i<n && a[i]<=s+r)  i++;
      int p = a[i-1];        //找到起始点s区间r内最后一个点 p 
      while(i<n && a[i]<=p+r)  i++;//寻找下一个起始点 
      sum++;
    }
    printf("%d\n",sum);
  }
    return 0;
}//2015-08-03 

2. POJ 3253

通过每次连接最短的两块板可以解决。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
int a[20005];
int main(void)
{
    //freopen("3253.in","r",stdin);
    int n;
    scanf("%d",&n);
    for(int i=0; i<n; i++)
  {
    scanf("%d",&a[i]);
  }
  long long res=0, t=0;
  while(n > 1)
  {
      int t1=0, t2=1;
      if(a[t1]>a[t2])    swap(t1,t2);
      for(int i=2; i<n; i++)
      {
          if(a[i]<a[t1])    swap(a[i], a[t1]);
          if(a[i]<a[t2])    swap(a[i], a[t2]);
      }    //找出最短板和次短板 
      t = a[t1]+a[t2];
      res+=t;
      a[t1]+=a[t2];
      if(t2!=n-1)        swap(a[t2], a[n-1]);
      n--;//将两块板连接 ,重复此步骤就可解决 
  }
  printf("%lld",res);
    return 0;
}//2015-08-04 

 练习题

2.1

POJ 1979

这道题还是比较简单的,主要要解决掉scanf最后的换行。

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstring>
 5 using namespace std;
 6 int vis[25][25];
 7 char s[25][25];
 8 int n, m, cou;//行数,列数,结果 
 9 void dfs(int x, int y)
10 {
11     //如果走出矩阵则返回 
12   if(x<0 || x>=m || y<0 || y>=n || s[x][y]=='#')  return;
13   if(vis[x][y]==1)  return;
14   vis[x][y] = 1;
15   if(s[x][y] == '.' || s[x][y] == '@')
16     cou++;
17   //四个方向搜索  
18           dfs(x, y-1);
19   dfs(x-1, y);      dfs(x+1, y);
20           dfs(x, y+1);
21 
22 }
23 int main(void)
24 {
25   int x, y;
26     //freopen("1979.in","r",stdin);
27     while(scanf("%d%d",&n,&m))
28   {
29     if(n==0 && m==0)  return 0;
30     getchar();    //吞掉多余的换行 
31     //标记数组清零 
32     memset(vis, 0, sizeof(vis));
33     cou = 0;
34     for(int i=0; i<m; i++)
35     {
36       for(int j=0; j<=n; j++)
37       {
38         scanf("%c",&s[i][j]);
39         if(s[i][j]=='@')
40         {
41           x = i;
42           y = j;
43         }
44       }
45     }
46     dfs(x, y);//从起点开始dfs 
47     printf("%d\n",cou);
48   }
49     return 0;
50 }

 POJ 3009

石头撞击墙壁后石头停下,墙壁破裂,还是暴力深搜,先判断能否直接到达终点,在搜索所有可行的走法。

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <cstring>
  5 using namespace std;
  6 int s[25][25];
  7 int result;
  8 int sx, sy;
  9 int n, m;
 10 void dfs(int x, int y, int step, int type)
 11 {
 12   if(step > 10)   return;    //超过10步失败 
 13   //到达目的地    
 14   if(s[x][y] == 3)
 15   {
 16     if(result == -1)  result = step;
 17     else  result = min(result, step);
 18     return;
 19   }
 20   //石头把墙撞碎 
 21   switch(type)
 22   {
 23       case 1:  s[x-1][y] = 0;  break; //north
 24     case 2:  s[x+1][y] = 0;  break; //south
 25     case 3:  s[x][y-1] = 0;  break;  //west
 26     case 4:  s[x][y+1] = 0;  break;  //east
 27   }
 28   //四处搜索寻找终点        
 29   for(int i=1; i<=x; i++)
 30   {   
 31       if(s[x-i][y]==1)    break;
 32       if(s[x-i][y]==3)  
 33         {
 34             dfs(x-i, y, step+1, 0);
 35             break;
 36         }
 37   }
 38   for(int i=1; i<m-x; i++)
 39   {
 40     if(s[x+i][y]==1)    break;
 41     if(s[x+i][y]==3)  
 42     {
 43         dfs(x+i, y, step+1, 0);
 44         break;
 45     }
 46   }              
 47   for(int i=1; i<=y; i++)
 48   {
 49       if(s[x][y-i]==1)    break;
 50     if(s[x][y-i]==3)  
 51     {
 52         dfs(x, y-i, step+1, 0);
 53         break;
 54     }
 55   }
 56   for(int i=1; i<n-y; i++)
 57   {
 58       if(s[x][y+i]==1)    break;
 59     if(s[x][y+i]==3) 
 60     {
 61         dfs(x, y+i, step+1, 0);
 62         break;
 63     }
 64   } 
 65   //四处探索 
 66   if(x>=1 && s[x-1][y]!=1)
 67         for(int i=2; i<=x; i++)
 68             if(s[x-i][y]==1)  
 69             {
 70                 dfs(x-i+1, y, step+1, 1);
 71                 break;
 72             }
 73   if(x+1<m && s[x+1][y]!=1)
 74       for(int i=2; i<m-x; i++)
 75           if(s[x+i][y]==1)  
 76             {
 77                 dfs(x+i-1, y, step+1, 2);
 78                 break;
 79             }    
 80   if(y>=1 && s[x][y-1]!=1)
 81         for(int i=2; i<=y; i++)
 82         if(s[x][y-i]==1)  
 83             {
 84                 dfs(x, y-i+1, step+1, 3);
 85                 break;
 86             }
 87     if(y+1<n && s[x][y+1]!=1)
 88         for(int i=2; i<n-y; i++)
 89         if(s[x][y+i]==1)  
 90             {
 91                 dfs(x, y+i-1, step+1, 4);    
 92                 break;
 93             }                                
 94   //墙壁复原 
 95   switch(type)
 96   {    
 97         case 1:  s[x-1][y] = 1;  break;
 98     case 2:  s[x+1][y] = 1;  break;
 99     case 3:  s[x][y-1] = 1;  break;
100     case 4:  s[x][y+1] = 1;  break;
101   }
102 }
103 int main(void)
104 {
105     //freopen("3009.in","r",stdin);
106     while(scanf("%d%d",&n,&m))  //m行n列
107   {
108     if(n==0 && m==0)  return 0;
109     result = -1;
110     for(int i=0; i<m; i++)
111       for(int j=0; j<n; j++)
112       {
113         scanf("%d",&s[i][j]);
114         if(s[i][j]==2) {sx=i; sy=j;}
115       }
116     dfs(sx, sy, 0, 0);
117     printf("%d\n",result);
118   }
119     return 0;
120 }

 

转载于:https://www.cnblogs.com/mycd/p/4702766.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值