《ACM國際大學生程序設計競賽題解Ⅰ》——基礎編程題

  這個專欄開始介紹一些《ACM國際大學生程序設計競賽題解》上的競賽題目,讀者能夠配合zju/poj/uva的在線測評系統提交代碼(今天zoj貌似崩了)。算法

  其實看書名也能看出來這本書的思路,就是一本題解書,簡單暴力的經過題目的堆疊來提高解決編程問題的能力。編程

  那麼下面開始探索吧。app

 

  poj1037:less

Descriptionide

Background
For years, computer scientists have been trying to find efficient solutions to different computing problems. For some of them efficient algorithms are already available, these are the "easy" problems like sorting, evaluating a polynomial or finding the shortest path in a graph. For the "hard" ones only exponential-time algorithms are known. The traveling-salesman problem belongs to this latter group. Given a set of N towns and roads between these towns, the problem is to compute the shortest path allowing a salesman to visit each of the towns once and only once and return to the starting point.
Problem
The president of Gridland has hired you to design a program that calculates the length of the shortest traveling-salesman tour for the towns in the country. In Gridland, there is one town at each of the points of a rectangular grid. Roads run from every town in the directions North, Northwest, West, Southwest, South, Southeast, East, and Northeast, provided that there is a neighbouring town in that direction. The distance between neighbouring towns in directions North-South or East-West is 1 unit. The length of the roads is measured by the Euclidean distance. For example, Figure 7 shows 2 * 3-Gridland, i.e., a rectangular grid of dimensions 2 by 3. In 2 * 3-Gridland, the shortest tour has length 6. 
Figure 7: A traveling-salesman tour in 2 ? 3-Gridland.

  題目大意:給出一個nxm的矩陣,如今從某點開始遍歷全部點並回到起始點,問最少的遍歷路程是多少?(從某點出發有8個方向,行上相鄰的點之間的距離是1。)ui

  數理分析:其實這道題目的描述很是有誤導性,屢次強調所謂「旅行銷售員問題」,也就是當如今尚未獲得很好解決的著名的TSP問題,這就很容易將人帶向很混亂的思惟。可是這道題目基於比較特殊的矩陣圖,咱們應該可以更加簡單的方法。this

  咱們首先應該考慮到的一個貪心策略,行走距離爲1的利益最大化就是訪問到了一個節點(固然不算起始節點),那麼若是有這樣一種方案使得咱們,遍歷距離+1,都會致使多訪問了1個節點,那麼這最終必定會致使最小的路程,即節點個數mn。lua

  那麼下面咱們所關注的問題即是,是否存在這樣一個策略呢?若是m列是偶數,那麼鏈接相鄰節點造成小正方格,就會造成奇數列個小方格,這使得咱們可以有一個走「S」型的鋸齒狀的遍歷策略,可以使咱們完成貪心策略。idea

  即咱們可以獲得結論,若是m、n當中有一個是偶數,最小距離都是mn。spa

  那麼若是m、n都是奇數呢?依然從m列入手,咱們基於(m-1)xn這樣一個矩陣,那麼咱們能夠採起和上面相似的思路進行貪心化的遍歷,由此咱們其實可以看到,對於這種狀況,是沒有一種路程爲mn的便利方案的,但對於剩下的兩列,一開始咱們令遍歷路線走一個長爲1.41的「斜邊」,而後由原來的縱向S型變成橫向S型,即路程爲mn + 0.41,這是除去路程爲mn的最優方案。

  上文給出的文字描述可能過於抽象,讀者能夠自行畫圖感覺一下。

  綜合起來咱們可以獲得這道問題線性算法:

  m、n存在一個偶數,結果是mn。

  否自,結果是mn + 0.41.

  簡單的參考代碼以下:

 

#include<cstdio>
using namespace std;

int main()
{
     int t;
     scanf("%d",&t);
     int tt  =1;
     while(t--)
     {
          int n , m;
          scanf("%d %d",&n,&m);
          if(n % 2 == 0 || m%2 == 0)
                printf("Scenario #%d:\n%d.00\n",tt++,m*n);
          else
                printf("Scenario #%d:\n%d.41\n",tt++,m*n);

          printf("\n");
     }
}

 

 

 poj1003:

 

Description

How far can you make a stack of cards overhang a table? If you have one card, you can create a maximum overhang of half a card length. (We're assuming that the cards must be perpendicular to the table.) With two cards you can make the top card overhang the bottom one by half a card length, and the bottom one overhang the table by a third of a card length, for a total maximum overhang of 1/2 + 1/3 = 5/6 card lengths. In general you can make n cards overhang by 1/2 + 1/3 + 1/4 + ... + 1/(n + 1) card lengths, where the top card overhangs the second by 1/2, the second overhangs tha third by 1/3, the third overhangs the fourth by 1/4, etc., and the bottom card overhangs the table by 1/(n + 1). This is illustrated in the figure below.

 

  題目大意:給出一個距離dis,表示堆在桌子上的撲克的伸出距離,問你至少須要多少張撲克可以堆出這個伸出距離。

  數理分析:其實這道題目的描述就是給出了咱們的解題方法,它告訴咱們n張撲克可以伸出的最遠距離是∑1/i,i∈[2,i+1],這就使得問題變得簡單了不少。可是這個問題的原始模型實際上是基於長度爲二、質量爲1的撲克的條件,它實際上是調和數的基本模型。若是讀者有興趣看一看這個計算公式怎麼得來的,能夠看一下筆者的《<具體數學>——特殊的數》一文中關於調和數的介紹。

  參考代碼以下。

 

#include<cstdio>
using namespace std;

int main()
{
     double dis;
     double temp,j;
     int i;
     while(scanf("%lf",&dis)!=EOF && dis != 0.00)
     {
                temp = 0;
              for(i = 2;;i++)
              {
                   j = (double)i;
                   temp += 1/j;
                      if(temp >= dis)
                           break;
              }

         printf("%d card(s)\n",i-1);

     }
}

 

poj1005:

 

Description

Fred Mapper is considering purchasing some land in Louisiana to build his house on. In the process of investigating the land, he learned that the state of Louisiana is actually shrinking by 50 square miles each year, due to erosion caused by the Mississippi River. Since Fred is hoping to live in this house the rest of his life, he needs to know if his land is going to be lost to erosion.
After doing more research, Fred has learned that the land that is being lost forms a semicircle. This semicircle is part of a circle centered at (0,0), with the line that bisects the circle being the X axis. Locations below the X axis are in the water. The semicircle has an area of 0 at the beginning of year 1. (Semicircle illustrated in the Figure.)

  題目大意:給出某點座標(x,y),而後圖示半圓從0開始,一年面積增長50,問多少年以後(x,y)會落在半圓上或者內部。
  數理分析:這道題目只要讀出半圓每一年增長50這個關鍵條件,而後注意輸出的語句格式,其他的部分並不困難。
  參考代碼以下:
 
#include<cstdio>
#include<cmath>
using namespace std;
const double pi = 3.1415926;

int main()
{
 double x , y , r;
 int t,i;
 scanf("%d",&t);
 int tt = 1;
 while(t--)
 {
    double temp = 0;
    scanf("%lf%lf",&x,&y);
       r = x*x + y*y;
      for(i = 1;;i++)
      {
            temp = (double)i*100/pi;
               if(temp >= r)
                   break;
      }
      printf("Property %d: This property will begin eroding in year %d.\n",tt++,i);
 }
 printf("END OF OUTPUT.");

}

 

tju1193:

When Issac Bernand Miller takes a trip to another country, say to France, he exchanges  his US dollars for French francs. The exchange rate is a real number such that  when multiplied by the number of dollars gives the number of francs. For example,  if the exchange rate for US dollars to French francs is 4.81724, then 10 dollars  is exchanged for 48.1724 francs. Of course, you can only get hundredth of a franc,  so the actual amount you get is rounded to the nearest hundredth. (We'll round  .005 up to .01.) All exchanges of money between any two countries are rounded  to the nearest hundredth. 

Sometimes Issac's trips take him to many countries and he exchanges money from   one foreign country for that of another. When he finally arrives back home,   he exchanges his money back for US dollars. This has got Issac thinking about   how much if his unspent US dollars is lost (or gained!) to these exchange rartes.   You'll compute how much money Issac ends up with if he exchanges it many times.   You'll always start with US dollars and you'll always end with US dollars.

Input

The first 5 lines of input will be the exchange rates between 5 countries,   numbered 1 through 5. Line i will five the exchange rate from country i to each   of the 5 countries. Thus the jth entry of line i will give the exchange rate   from the currency of country i to the currency of country j. the exchange rate   form country i to itself will always be 1 and country 1 will be the US. Each   of the next lines will indicate a trip and be of the form

N c1 c2 ... cn m

Where 1 ≤ n ≤ 10 and c1, ..., cn are integers from 2 through 5 indicating   the order in which Issac visits the countries. (A value of n = 0 indicates end   of input, in which case there will be no more numbers on the line.) So, his   trip will be 1 -> c1 -> c2 -> ... -> cn -> 1. the real number m   will be the amount of US dollars at the start of the trip.

Output

Each trip will generate one line of output giving the amount of US dollars   upon his return home from the trip. The amount should be fiven to the nearest   cent, and should be displayed in the usual form with cents given to the right   of the decimal point, as shown in the sample output. If the amount is less than   one dollar, the output should have a zero in the dollars place.

 

  題目大意:一次給出序號爲一、二、三、四、5這5個國家之間的貨幣匯率,而後給出周遊順序<c1,c2,c3...cn>,每到一個國家,咱們都將原有的外幣換成這個國家的錢,那麼給出初始金額m的狀況下,完成<1,c1,...cn,1>,最終手頭的錢會變成多少,結果應四捨五入至百分位。

  數理分析:在理解了題意以後,可以看到這是一道很基礎的模擬題目。須要注意的細節是,所謂四捨五入至百分位,是要求每次交換都按照這個要求,而不是獲得最終的money而後四捨五入,兩者在屢次交換後會產生可見的偏差。第3組數據就是明顯的例子。

  簡單的參考代碼以下:

 

#include<cstdio>
using namespace std;

double rate[6][6];
int country[15];

int main()
{
     int t,n;

           for(int i = 1;i <= 5;i++)
               for(int j = 1;j <= 5;j++)
                  scanf("%lf",&rate[i][j]);

            double money;
            while(scanf("%d",&n) && n != 0)
            {


            country[n+2] = 1;
            country[1] = 1;
            for(int i  = 2;i <= n + 1;i++)
                   scanf("%d",&country[i]);
                scanf("%lf",&money);
            for(int i = 1;i <= n + 1;i++)
            {
                  money *= rate[country[i]][country[i+1]];
                  money = (int)(money*100 + 0.5);    //每次交換都應該進行百分位的四捨五入
                  money /= 100;
            }
         printf("%.2lf\n",money);
            }

}

 

poj1046:

Description

A color reduction is a mapping from a set of discrete colors to a smaller one. The solution to this problem requires that you perform just such a mapping in a standard twenty-four bit RGB color space. The input consists of a target set of sixteen RGB color values, and a collection of arbitrary RGB colors to be mapped to their closest color in the target set. For our purposes, an RGB color is defined as an ordered triple (R,G,B) where each value of the triple is an integer from 0 to 255. The distance between two colors is defined as the Euclidean distance between two three-dimensional points. That is, given two colors (R1,G1,B1) and (R2,G2,B2), their distance D is given by the equation

Input

The input is a list of RGB colors, one color per line, specified as three integers from 0 to 255 delimited by a single space. The first sixteen colors form the target set of colors to which the remaining colors will be mapped. The input is terminated by a line containing three -1 values.

Output

For each color to be mapped, output the color and its nearest color from the target set.
If there are more than one color with the same smallest distance, please output the color given first in the color set
 
  題目大意:首先給出16個三元實數對(R,G,B),而後鍵盤輸入某個三元組(r,g,b),求解(r,g,b)與這16個當中哪一個三元組「距離」最小,距離公式題目中已經給出。
  數理分析:其實這種類型的題目在讀出題意以後,將其簡化得描述出來,會發現是很基礎的題目。
  簡單的參考代碼以下:
 
#include<cstdio>
using namespace std;

struct color
{
    int  r ,g ,b;
}a[10000];
int main()
{
      for(int i = 1;i <= 16;i++)
          scanf("%d%d%d",&a[i].r,&a[i].g,&a[i].b);


      int rr , gg , bb;
      while(scanf("%d%d%d",&rr,&gg,&bb)  && rr+gg+bb >= 0)
            {
                   int Min = 99999999;
                   int temp , tempi;
                   for(int i = 1;i <= 16;i++)
                      {
                            temp = (a[i].r-rr)*(a[i].r-rr) + (a[i].g-gg)*(a[i].g-gg) + (a[i].b-bb)*(a[i].b-bb);
                            if(temp < Min)
                            {
                                 Min = temp;
                                 tempi = i;
                            }
                      }
                 printf("(%d,%d,%d) maps to (%d,%d,%d)\n",rr,gg,bb,a[tempi].r,a[tempi].g,a[tempi].b);
            }
}

 

zoj1078:

  Statement of the Problem

We say that a number is a palindrom if it is the sane when read from left to right or from right to left. For example, the number 75457 is a palindrom.

Of course, the property depends on the basis in which is number is represented. The number 17 is not a palindrom in base 10, but its representation in base 2 (10001) is a palindrom.

The objective of this problem is to verify if a set of given numbers are palindroms in any basis from 2 to 16.

Input Format

Several integer numbers comprise the input. Each number 0 < n < 50000 is given in decimal basis in a separate line. The input ends with a zero.

Output Format

Your program must print the message Number i is palindrom in basis where I is the given number, followed by the basis where the representation of the number is a palindrom. If the number is not a palindrom in any basis between 2 and 16, your program must print the message Number i is not palindrom.

 

  題目大意:給出一個十進制數字n,判斷n在x進制下是否會問,x∈[2,16],並輸出x。

  數理分析:這道題目分爲兩個步驟,第一是進制轉化,第二是判斷迴文。判斷迴文根據其定義進行模擬判斷便可,下面說一下如何進行進制轉化。

  咱們知道,整數x表示成r進制的形式爲,x = x1*r^0 + x2*r^1 + x3*r^2 +...,那麼咱們採起相似快速冪的過程,經過計算x%r,咱們可以獲得x1,隨後咱們令x = x/r,再計算x%r將獲得x2......依次類推,即可獲得r進制數x。

  簡單的參考代碼以下。

 

#include<cstdio>
using namespace std;

int main()
{
      int n;
      int i , j;
      while(scanf("%d",&n) && n)
      {
           int sign = 0;
           char c[30];
           int base[17] = {0};
           for(i = 2;i <= 16;i++)
           {
                int m = n;
                int len = 0;
                while(m)
                {
                    c[len++] = m%i;
                    m = m/i;
                }
                sign = 1;
                for(j = 0;j <len/2 &sign ;j++)
                       if(c[j] != c[len-j-1])  sign = 0;
                if(sign)  base[i] = 1;

           }

             sign = 1;
             for(i = 2;i <= 16;i++)
                  if(base[i] == 1)  sign = 0;
             if(sign)
                   printf("Number %d is not a palindrom\n",n);
             else
               {
                   printf("Number %d is palindrom in basis",n);
                   for(i = 2;i <= 16;i++)
                           if(base[i] == 1)
                              printf(" %d",i);
                    printf("\n");
               }
      }
}
相關文章
相關標籤/搜索