算法-藍橋杯習題(5-1)

 

藍橋杯習題

 

目錄

 

入門訓練(詳見 算法-藍橋杯習題(1-1)Go

 

基礎練習(詳見 算法-藍橋杯習題(2-1)Go

基礎練習(詳見 算法-藍橋杯習題(2-2)Go

算法訓練(詳見 算法-藍橋杯習題(3-1)Go

算法訓練(詳見 算法-藍橋杯習題(3-2)Go

算法訓練(詳見 算法-藍橋杯習題(3-3)Go

算法訓練(詳見 算法-藍橋杯習題(3-4)Go

算法訓練(詳見 算法-藍橋杯習題(3-5)Go

算法訓練(詳見 算法-藍橋杯習題(3-6)Go

算法提高(詳見 算法-藍橋杯習題(4-1)Go

算法提高(詳見 算法-藍橋杯習題(4-2)Go

算法提高(詳見 算法-藍橋杯習題(4-3)Go

 

歷屆試題(詳見 算法-藍橋杯習題(5-1)Go

 

歷屆試題(詳見 算法-藍橋杯習題(5-2)Go

 

藍橋杯練習系統評測數據

鏈接: https://pan.baidu.com/s/1brjjmwv
密碼: iieq

 

歷屆試題(PartA-10題)

鏈接: http://pan.baidu.com/s/1o7bzkAu 

密碼: 4twx

歷屆試題(PartB-10題)

鏈接: http://pan.baidu.com/s/1gdUlRsZ 

密碼: x255

 

歷屆試題(PartA-10題)

 

 

 

/*
歷屆試題 核桃的數量

問題描述
小張是軟件項目經理,他帶領3個開發組。工期緊,今天都在加班呢。爲鼓舞士氣,小張打算給每個組發一袋核桃(據傳言能補腦)。他的要求是:

1. 各組的核桃數量必須相同

2. 各組內必須能平分核桃(當然是不能打碎的)

3. 儘量提供滿足1,2條件的最小數量(節約鬧革命嘛)

輸入格式
輸入包含三個正整數a, b, c,表示每個組正在加班的人數,用空格分開(a,b,c<30)
輸出格式
輸出一個正整數,表示每袋核桃的數量。
樣例輸入1
2 4 5
樣例輸出1
20
樣例輸入2
3 1 1
樣例輸出2
3
*/
#include <stdio.h>
main()
{
    int a,b,c,s;
    do
    {
        scanf("%d%d%d", &a,&b,&c);
    }                                   
    while(a>30&&b>30&&c>30);                                    
    s=f1(a,b);
   // printf("%d\n",s);
    s=f1(s,c);
    printf("%d\n",s);
    return 0;
}

int f1(int a,int b)
{
    int t,m;
    int c;
    if (a < b)                                              
    {
        t = a;
        a = b;
        b = t;
    }
    m = a * b;
    
    
    c = a % b;                                          
    while (c != 0)                                      
    {
        a = b;                                              
        b = c;                                          
        c = a % b;                                      
    }
    
    return m/b;
}

 

/*
歷屆試題 打印十字圖

問題描述
小明爲某機構設計了一個十字型的徽標(並非紅十字會啊),如下所示:

對方同時也需要在電腦dos窗口中以字符的形式輸出該標誌,並能任意控制層數。

輸入格式
一個正整數 n (n<30) 表示要求打印圖形的層數。
輸出格式
對應包圍層數的該標誌。
樣例輸入1
1
樣例輸出1

樣例輸入2
3
樣例輸出2

提示
請仔細觀察樣例,尤其要注意句點的數量和輸出位置。
*/
//更好的解法 http://codepad.org/EztNVCs7 
#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace std;
 
const
  int SPACE = '.';
  int STAR  = '$';

 
// 獲取每行的字符數
int getRowLength(int layerCount)
{
   return 5 + layerCount * 4;
}

// 初始化
void clearAll(char* buf, int layerCount)
{

  int size = getRowLength(layerCount);

  size = size * size;

  for (int i=0; i<size; i++)

    buf[i] = SPACE;

}

// 顯示圖案
void drawAll(char* buf, int layerCount)
{

  int rowLen = getRowLength(layerCount);

  char* pbuf = buf;

  for (int i=0; i<rowLen; i++)

  {

    for (int j=0; j<rowLen; j++)

      printf("%c", *pbuf++);

    printf("\n");

  }

}

// 畫橫線
void drawHLine(char* buf, int layerCount, int x1, int x2, int y)
{
     
  int rowLen = getRowLength(layerCount);

  for (int i = x1; i <= x2; i++)

    buf[i + rowLen * y] = STAR;

}

// 畫豎線
void drawVLine(char* buf, int layerCount, int x, int y1, int y2)
{

  int rowLen = getRowLength(layerCount);

  for (int i = y1; i <= y2; i++)

    buf[x + i * rowLen] = STAR;

}

// 畫中心十字
void drawCenter(char* buf, int layerCount)
{
  //每行的字符數 
  int x, y, rowLen = getRowLength(layerCount);

  x = rowLen / 2; //中心的座標 

  y = rowLen / 2; //中心的座標

  drawHLine(buf, layerCount, x-2, x+2, y);

  drawVLine(buf, layerCount, x, y-2, y+2);

}

 

// 畫第layer層
void drawLayer(char* buf, int layer, int layerCount)
{

  int cx, cy, n, offset, rowLen = getRowLength(layerCount);

  cx = rowLen / 2;

  cy = rowLen / 2;

  n = layer * 2;

  offset = 2 + layer * 2;

  drawVLine(buf, layerCount, cx - offset, cy - n, cy + n);

  drawVLine(buf, layerCount, cx + offset, cy - n, cy + n);

  drawHLine(buf, layerCount, cx - n, cx + n, cy - offset);

  drawHLine(buf, layerCount, cx - n, cx + n, cy + offset);

  drawVLine(buf, layerCount, cx - n, cy - offset, cy - offset + 2);

  drawVLine(buf, layerCount, cx + n, cy - offset, cy - offset + 2);

  drawVLine(buf, layerCount, cx - n, cy + offset - 2, cy + offset);

  drawVLine(buf, layerCount, cx + n, cy + offset - 2, cy + offset);

  drawHLine(buf, layerCount, cx - n - 2, cx - n, cy - n);

  drawHLine(buf, layerCount, cx + n, cx + n + 2, cy - n);

  drawHLine(buf, layerCount, cx - n - 2, cx - n, cy + n);

  drawHLine(buf, layerCount, cx + n, cx + n + 2, cy + n);

}

// 返回n層需要的緩存區大小
int getBufferSize(int layerCount)
{

  int rowLen = getRowLength(layerCount);

  return rowLen * rowLen;

}

int main()
{
  int layerCount;
  while (scanf("%d", &layerCount) != EOF)    // 讀層數
  {
    if (layerCount <= 0)
      break;

    char* buf = (char *)malloc(getBufferSize(layerCount));    // 申請緩存區

    clearAll(buf, layerCount);        // 圖案初始化

    drawCenter(buf, layerCount);    // 畫中心十字
    drawLayer(buf, 1, layerCount);

    for (int i=1; i<=layerCount; i++)    // 畫所有層
    { 
      drawLayer(buf, i, layerCount);
    } 
    
    drawAll(buf, layerCount);            // 顯示圖案

    free(buf);

  }
   system("PAUSE");

   return 0;

}

 

/*
歷屆試題 帶分數

問題描述
100 可以表示爲帶分數的形式:100 = 3 + 69258 / 714。

還可以表示爲:100 = 82 + 3546 / 197。

注意特徵:帶分數中,數字1~9分別出現且只出現一次(不包含0)。

類似這樣的帶分數,100 有 11 種表示法。

輸入格式
從標準輸入讀入一個正整數N (N<1000*1000)

輸出格式
程序輸出該數字用數碼1~9不重複不遺漏地組成帶分數表示的全部種數。

注意:不要求輸出每個表示,只統計有多少表示法!

樣例輸入1
100
樣例輸出1
11
樣例輸入2
105
樣例輸出2
6
*/
#include <stdio.h>
#include <stdlib.h>

typedef struct Interval
{
    int pre;
    int rear;
    int satisfy;
}Interval;
Interval interval[7][5];
int count=0;

//初始化
void Init()
{
    int i,j;
    int value;
    for(i=1;i<7;i++)
    {
        value=i;
        for(j=1;j<5;j++)
        {
            interval[i][j].pre=value++;
            interval[i][j].rear=value;
        }
    }
}

//數組初始化爲0
void InitZero(int *sign)
{
    int i;
    sign[0]=1;
    for(i=1;i<10;i++)
    {
        sign[i]=0;
    }
}

//將一個數的各個位上拆分,並在相應的位上賦值1
int Split(int *sign,int value)
{
    int index;
    while(value)
    {
        index=value%10;
        if(sign[index]==0) sign[index]=1;
        else return 1;
        value/=10;
    }
    return 0;
}

//計算一個數的位數
int CountBit(int value)
{
    int n=0;
    while(value)
    {
        n++;
        value/=10;
    }
    return n;
}

//將一個整型數組轉換成一個整數
int CreateInteger(int *data,int n)
{
    int i;
    int value=0;
    for(i=0;i<n;i++)
    {
        value=value*10+data[i];
    }
    return value;
}

//檢查是否每個數都用到
int Check(int *sign)
{
    int i;
    for(i=1;i<10;i++)
    {
        if(sign[i]==0) return 0;
    }
    return 1;
}

//複製
void Copy(int *sign,int *temp_sign)
{
    int i;
    for(i=0;i<10;i++)
    {
        temp_sign[i]=sign[i];
    }
}
//創建一個n位數的整數
void CreateNBitNumber(int *sign,int *data,int n,int m,int value,int value3)
{
    if(n==m)
    {
        int value1=CreateInteger(data,n);
        int value2=value1*value;
        int temp_sign[10];
        Copy(sign,temp_sign);
        if(!Split(temp_sign,value2) && Check(temp_sign))
        {
            count++;
        }
    }
    else
    {
        int i;
        for(i=1;i<10;i++)
        {
            if(sign[i]==0)
            {
                sign[i]=1;
                data[m]=i;
                CreateNBitNumber(sign,data,n,m+1,value,value3);
                sign[i]=0;
            }
        }
    }
}

//求出解
void Create(int value)
{
    int i,j;
    int sign[10];
    int result;
    int result_n;
    int n;
    for(i=3;i<value;i++)
    {
        InitZero(sign);
        if(Split(sign,i)) continue;
        result=value-i;
        result_n=CountBit(result);
        n=CountBit(i);
        for(j=1;j<5;j++)
        {
            if( ((interval[result_n][j].pre+j)==(9-n)) || ((interval[result_n][j].rear+j)==(9-n)))
            {
                int data[5];
                CreateNBitNumber(sign,data,j,0,result,i);
            }
        }
    }
}

int main()
{
    int value;
    scanf("%d",&value);
    Init();
    Create(value);
    printf("%d\n",count);
    return 0;
}

 

/*
歷屆試題 剪格子

問題描述
如下圖所示,3 x 3 的格子中填寫了一些整數。

+--*--+--+
|10* 1|52|
+--****--+
|20|30* 1|
*******--+
| 1| 2| 3|
+--+--+--+
我們沿着圖中的星號線剪開,得到兩個部分,每個部分的數字和都是60。

本題的要求就是請你編程判定:對給定的m x n 的格子中的整數,是否可以分割爲兩個部分,使得這兩個區域的數字和相等。

如果存在多種解答,請輸出包含左上角格子的那個區域包含的格子的最小數目。

如果無法分割,則輸出 0。

輸入格式
程序先讀入兩個整數 m n 用空格分割 (m,n<10)。

表示表格的寬度和高度。

接下來是n行,每行m個正整數,用空格分開。每個整數不大於10000。

輸出格式
輸出一個整數,表示在所有解中,包含左上角的分割區可能包含的最小的格子數目。
樣例輸入1
3 3
10 1 52
20 30 1
1 2 3
樣例輸出1
3
樣例輸入2
4 3
1 1 1 1
1 30 80 2
1 1 1 100
樣例輸出2
10
*/
#include <stdio.h>
#define N 10
int num[N][N];
int tag[N][N] = {0};
int m, n;
int r = 100;
int find(int i, int j, int t, int ntag[][N])
{ 
    int count = 0;
    if (i < 0 || i >= n || j < 0 || j >= m || ntag[i][j] == 1)
        return 0; 
    ntag[i][j] = 1;
    if (tag[i][j] != t)
        return 0;
    count++;
    count += find(i - 1, j, t, ntag);
    count += find(i + 1, j, t, ntag);
    count += find(i, j - 1, t, ntag);
    count += find(i, j + 1, t, ntag);
    return count;
}
 
int isbad()
{
    int i, j, k = 0,ge2;
    int t = tag[0][0];
    int ntag1[N][N] = {0};
    int ntag2[N][N] = {0};  
    int ge1 = find(0, 0, t, ntag1);
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < m; j++)
        {
            if (tag[i][j] != t)
            {
                k = 1;
                break;
            }
        }
        if (k == 1)
            break; 
    }
    
    if (i == n && j == m)
        return 0;
     ge2 = find(i, j, tag[i][j], ntag2);

    return ge1 + ge2 != m * n;
}
int bad(int i, int j)
{
   int b;
    if (i < 0 || i >= n || j < 0 || j >= m || tag[i][j] == 1)
        return 1;
        
    tag[i][j] = 1; 
    b = isbad();  
    tag[i][j] = 0;  
    return b;
}

void go(int i, int j, int k, int count)
{
    
    if (bad(i, j) || count < num[i][j])
        return;
    k++;
   
    if (count == num[i][j])
    {
        if (r > k)
            r = k;
        return; 
    }
    
  
    tag[i][j] = 1;
    count -= num[i][j];
    go(i - 1, j, k, count); 
    go(i + 1, j, k, count);
    go(i, j - 1, k, count); 
    go(i, j + 1, k, count);
    tag[i][j] = 0;
}

int main()
{
    
    int i, j;
    int half = 0;
    scanf("%d %d", &m, &n);
    for (i = 0; i < n; i++)
        for (j = 0; j < m; j++)
        {
            scanf("%d", &num[i][j]);
 
            half += num[i][j];
        }
    
 
    if (half % 2 == 0 && half >= num[0][0] * 2)
    {
       
        half /= 2;
        go(0, 0, 0, half);
    }
    
    if (r == 100)
        r = 0;
    
    printf("%d", r);

    return 0;
}

 

/*
歷屆試題 錯誤票據

問題描述
某涉密單位下發了某種票據,並要在年終全部收回。

每張票據有唯一的ID號。全年所有票據的ID號是連續的,但ID的開始數碼是隨機選定的。

因爲工作人員疏忽,在錄入ID號的時候發生了一處錯誤,造成了某個ID斷號,另外一個ID重號。

你的任務是通過編程,找出斷號的ID和重號的ID。

假設斷號不可能發生在最大和最小號。

輸入格式
要求程序首先輸入一個整數N(N<100)表示後面數據行數。

接着讀入N行數據。

每行數據長度不等,是用空格分開的若干個(不大於100個)正整數(不大於100000),請注意行內和行末可能有多餘的空格,你的程序需要能處理這些空格。

每個整數代表一個ID號。

輸出格式
要求程序輸出1行,含兩個整數m n,用空格分隔。

其中,m表示斷號ID,n表示重號ID

樣例輸入1
2
5 6 8 11 9 
10 12 9
樣例輸出1
7 9
樣例輸入2
6
164 178 108 109 180 155 141 159 104 182 179 118 137 184 115 124 125 129 168 196
172 189 127 107 112 192 103 131 133 169 158 
128 102 110 148 139 157 140 195 197
185 152 135 106 123 173 122 136 174 191 145 116 151 143 175 120 161 134 162 190
149 138 142 146 199 126 165 156 153 193 144 166 170 121 171 132 101 194 187 188
113 130 176 154 177 120 117 150 114 183 186 181 100 163 160 167 147 198 111 119
樣例輸出2
105 120
*/
#include <stdio.h>    
int main()  
{  
    int a[10001]={0};
    long m,min=100000,max=0,i,n;
    char c;
    scanf("%d",&n);
        for(i=0;i<n;i++)
            while(1)
            {
            scanf("%ld",&m);
            if(m>max) max=m;
            if(m<min) min=m;
            a[m]++;
            c=getchar();
            if(c!=' ') break;
            }

    for(i=min;i<=max;i++)
    {
     if(a[i]==0) printf("%ld ",i);
     if(a[i]==2) m=i;
    }
      printf("%ld",m);
    
    return 0;
}
/*
歷屆試題 翻硬幣

問題描述
小明正在玩一個“翻硬幣”的遊戲。

桌上放着排成一排的若干硬幣。我們用 * 表示正面,用 o 表示反面(是小寫字母,不是零)。

比如,可能情形是:**oo***oooo

如果同時翻轉左邊的兩個硬幣,則變爲:oooo***oooo

現在小明的問題是:如果已知了初始狀態和要達到的目標狀態,每次只能同時翻轉相鄰的兩個硬幣,那麼對特定的局面,最少要翻動多少次呢?

我們約定:把翻動相鄰的兩個硬幣叫做一步操作,那麼要求:

輸入格式
兩行等長的字符串,分別表示初始狀態和要達到的目標狀態。每行的長度<1000

輸出格式
一個整數,表示最小操作步數。

樣例輸入1
**********
o****o****
樣例輸出1
5
樣例輸入2
*o**o***o***
*o***o**o***
樣例輸出2
1
*/
//author :C博客用戶 qq_332040812
# include <stdio.h>
# include <stdlib.h>
# include <string.h> 
char str1[1000];
char str2[1000];
int main(void)
{
	int len = 0,i,t = 0,sum = 0,c = 0;
	scanf("%s",str1);
	scanf("%s",str2);
	len = strlen(str1);
	for(i = 0; i < len; ++i)
	{
		if( str1[i] != str2[i] )
		{
			t = i - t;
			++c;
		}
		if(c == 2)
		{	
			c = 0;
			sum +=t;
			t = 0;
		}
	}
	printf("%d",sum);
	return 0;
}

/*
#include <stdio.h>
#include <string.h>
#define MaxSize 1005

void getResult(char *start,char *end)
{
	int len=strlen(start);
	int i;
	int count=0;
	int flag1[MaxSize]={0},flag2[MaxSize]={0};
	
	//printf("字符串長度%d\n",len);
	
	//memset(flag1,1,sizeof(int));
	//memset(flag2,1,sizeof(int));
	
	//

	for(i=0;i<len;i++)
	{
		if(start[i]=='o')
		{
			flag1[i]=1;
		}
		if(end[i]=='o')
		{
			flag2[i]=1;
		}
	}
	
	for(i=0;i<len-1;i++)
	{
		if(flag1[i]!=flag2[i])
		{
			flag1[i]=!flag1[i];
			flag1[i+1]=!flag1[i+1];
			count++;
		}
	}
	if(flag1[len-1]!=flag2[len-1])
	{
		count++;
	}

	printf("%d\n",count);
	
	return ;
}

main()
{
	char start[MaxSize],end[MaxSize];
	
	gets(start);
	gets(end);
	
	getResult(start,end);
	
	return 0;
}
*/

 

/*
歷屆試題 連號區間數

問題描述
小明這些天一直在思考這樣一個奇怪而有趣的問題:

在1~N的某個全排列中有多少個連號區間呢?這裏所說的連號區間的定義是:

如果區間[L, R] 裏的所有元素(即此排列的第L個到第R個元素)遞增排序後能得到一個長度爲R-L+1的“連續”數列,則稱這個區間連號區間。

當N很小的時候,小明可以很快地算出答案,但是當N變大的時候,問題就不是那麼簡單了,現在小明需要你的幫助。

輸入格式
第一行是一個正整數N (1 <= N <= 50000), 表示全排列的規模。

第二行是N個不同的數字Pi(1 <= Pi <= N), 表示這N個數字的某一全排列。

輸出格式
輸出一個整數,表示不同連號區間的數目。

樣例輸入1
4
3 2 4 1
樣例輸出1
7
樣例輸入2
5
3 4 2 5 1
樣例輸出2
9
*/
#include<stdio.h>
int main()
{
    int s[50005],a,i,min,max,count=0,j;
    scanf("%d",&a);
    for( i = 0; i < a; i++) {
        scanf("%d",&s[i]);
    }
    for( i = 0; i <a;i++ ){ 
        min=s[i];
        max=s[i];
        for( j = i; j <a; j++) {
            if(min>s[j]){min =s[j];}
            if(max<s[j]){max =s[j];}
            if((max-min)==(j-i)){
                count++;
            }

        }
    }
    printf("%d",count);
    return 0;
}

 

/*
歷屆試題 買不到的數目

問題描述
小明開了一家糖果店。他別出心裁:把水果糖包成4顆一包和7顆一包的兩種。糖

果不能拆包賣。

小朋友來買糖的時候,他就用這兩種包裝來組合。當然有些糖果數目是無法組合

出來的,比如要買 10 顆糖。

你可以用計算機測試一下,在這種包裝情況下,最大不能買到的數量是17。大於

17的任何數字都可以用4和7組合出來。

本題的要求就是在已知兩個包裝的數量時,求最大不能組合出的數字。

輸入格式
兩個正整數,表示每種包裝中糖的顆數(都不多於1000)

輸出格式
一個正整數,表示最大不能買到的糖數

樣例輸入1
4 7
樣例輸出1
17
樣例輸入2
3 5
樣例輸出2
7

a*b-a-b證明過程?百度
*/
#include <stdio.h>

main()
{
    int a,b;
    
    scanf("%d%d",&a,&b);
    printf("%d\n",a*b-a-b);
    
    return 0;
}

 

/*
歷屆試題 大臣的旅費

問題描述
很久以前,T王國空前繁榮。爲了更好地管理國家,王國修建了大量的快速路,用於連接首都和王國內的各大城市。

爲節省經費,T國的大臣們經過思考,制定了一套優秀的修建方案,使得任何一個大城市都能從首都直接或者通過其他大城市間接到達。同時,如果不重複經過大城市,從首都到達每個大城市的方案都是唯一的。

J是T國重要大臣,他巡查於各大城市之間,體察民情。所以,從一個城市馬不停蹄地到另一個城市成了J最常做的事情。他有一個錢袋,用於存放往來城市間的路費。

聰明的J發現,如果不在某個城市停下來修整,在連續行進過程中,他所花的路費與他已走過的距離有關,在走第x千米到第x+1千米這一千米中(x是整數),他花費的路費是x+10這麼多。也就是說走1千米花費11,走2千米要花費23。

J大臣想知道:他從某一個城市出發,中間不休息,到達另一個城市,所有可能花費的路費中最多是多少呢?

輸入格式
輸入的第一行包含一個整數n,表示包括首都在內的T王國的城市數

城市從1開始依次編號,1號城市爲首都。

接下來n-1行,描述T國的高速路(T國的高速路一定是n-1條)

每行三個整數Pi, Qi, Di,表示城市Pi和城市Qi之間有一條高速路,長度爲Di千米。

輸出格式
輸出一個整數,表示大臣J最多花費的路費是多少。

樣例輸入1
5
1 2 2
1 3 1
2 4 5
2 5 4
樣例輸出1
135
輸出格式
大臣J從城市4到城市5要花費135的路費。
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>

struct node;
typedef struct node Node;
typedef Node *PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;

struct node
{
int n;
int val;
Position next;
};

int count=0;
int max=0;
int x;
int *visit; //是否已遍歷

Position Last(List l); //找出最後項
void Insert(int x,int q,List l,Position p); //在p後插入含x的項
void Dfs(int a,List l[]); //深度優先搜索
int Num(List l);

int main(void)
{
int n,u,v,q,a,b;
int i,j,k;
Node *head;
List *l,tmp;
Position p;

fscanf(stdin,"%d",&n);
head=(Node *)malloc(sizeof(Node)*(n+1));
l=(List *)malloc(sizeof(List)*(n+1));
visit=(int *)malloc(sizeof(int)*(n+1));

for(i=0;i<=n;i++) //初始化表頭及鏈表
{
head[i].next=NULL;
l[i]=&head[i];
}

for(i=1;i<=n-1;i++) //建立無向圖
{
fscanf(stdin,"%d%d%d",&u,&v,&q);
Insert(v,q,l[u],Last(l[u]));
Insert(u,q,l[v],Last(l[v]));
}

for(j=1;j<=n;j++)
visit[j]=0;
Dfs(1,l); //第一次遍歷,找到點a,用全局變量x保存

for(j=1;j<=n;j++)
visit[j]=0;
count=0;
max=0;
Dfs(x,l); //第二次遍歷,找到點b,用全局變量x保存,此時max爲最大距離

printf("%d",max*10+(max+1)*max/2);

return 0;
}

Position Last(List l)
{
Position p;
for(p=l;p->next!=NULL;p=p->next);
return p;
}

void Insert(int x,int q,List l,Position p)
{
Position tmp;
tmp=(Position) malloc(sizeof(Node));

tmp->n=x;
tmp->val=q;
tmp->next=p->next;
p->next=tmp;
}

void Dfs(int a,List l[])
{
Position p;

visit[a]=1;
for(p=l[a]->next;p!=NULL;p=p->next)
if(!(visit[p->n]))
{
count+=p->val;
if(count>max)
{
max=count;
x=p->n;
}

Dfs(p->n,l);
count-=p->val;
}
}

int Num(List l)
{
int n=0;
Position p;
for(p=l->next;p!=NULL;p=p->next)
n++;
return n;
}

 

/*
歷屆試題 幸運數

問題描述
幸運數是波蘭數學家烏拉姆命名的。它採用與生成素數類似的“篩法”生成

。
首先從1開始寫出自然數1,2,3,4,5,6,....

1 就是第一個幸運數。

我們從2這個數開始。把所有序號能被2整除的項刪除,變爲:

1 _ 3 _ 5 _ 7 _ 9 ....

把它們縮緊,重新記序,爲:

1 3 5 7 9 .... 。這時,3爲第2個幸運數,然後把所有能被3整除的序號位置的數刪去。注意,是序號位置,不是那個數本身能否被3整除!! 刪除的應該是5,11, 17, ...

此時7爲第3個幸運數,然後再刪去序號位置能被7整除的(19,39,...)

最後剩下的序列類似:

1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 49, 51, 63, 67, 69, 73, 75, 79, ...

輸入格式
輸入兩個正整數m n, 用空格分開 (m < n < 1000*1000)
輸出格式
程序輸出 位於m和n之間的幸運數的個數(不包含m和n)。
樣例輸入1
1 20
樣例輸出1
5
樣例輸入2
30 69
樣例輸出2
8
*/
#include<stdio.h>
#define MAXN 1000010
int flag[MAXN];
int m,n,a[MAXN],s[MAXN],size=0;
int fa(int k)
{
    if(flag[k])
        return a[k];
    return fa(k-1);
}
int main()
{
    int i, p, k, j;
    scanf("%d%d",&m,&n);
    for(i=1;i<=n;i+=2)
    {
        s[++size]=i; 
        flag[i]=1; 
        a[i]=size;
    }
    for(i=2;i<=size;i++)
    {
        int Mod=s[i],d=s[i]-1;
        if(Mod>size)
            break;
        for(p=1,j=Mod;j<=size;j+=Mod,p++)
        {
            flag[s[j]]=0;
            for(k=1;k<Mod&&k+j<=size;k++)
            {
                s[++d]=s[j+k];
                a[s[j+k]]-=p;
            }
        }
        size=d;
    }
    printf("%d\n",fa(n-1)-fa(m));
    return 0;
}


歷屆試題(PartB-10題)

 

 

 

 

 

 

/*
歷屆試題 橫向打印二叉樹

問題描述
二叉樹可以用於排序。其原理很簡單:對於一個排序二叉樹添加新節點時,先與根節點比較,若小則交給左子樹繼續處理,否則交給右子樹。

當遇到空子樹時,則把該節點放入那個位置。

比如,10 8 5 7 12 4 的輸入順序,應該建成二叉樹如下圖所示,其中.表示空白。

...|-12
10-|
...|-8-|
.......|...|-7
.......|-5-|
...........|-4
本題目要求:根據已知的數字,建立排序二叉樹,並在標準輸出中橫向打印該二叉樹。

輸入格式
輸入數據爲一行空格分開的N個整數。 N<100,每個數字不超過10000。

輸入數據中沒有重複的數字。

輸出格式
輸出該排序二叉樹的橫向表示。爲了便於評卷程序比對空格的數目,請把空格用句點代替:

樣例輸入1
10 5 20
樣例輸出1
...|-20
10-|
...|-5
樣例輸入2
5 10 20 8 4 7
樣例輸出2
.......|-20
..|-10-|
..|....|-8-|
..|........|-7
5-|
..|-4

*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct TNode
{
    int key;
    struct TNode *left;
    struct TNode *right;
}TNode, *Tree;

Tree insert(Tree root, Tree src)
{
    if(root == NULL)
    {
        root = src;
    }
    else if(src->key > root->key)
    {
        root->left = insert(root->left, src);
    }
    else
    {
        root->right = insert(root->right, src);
    }
    return root;
}

char l[1000];

#define U 1
#define D 2
#define S ('.')

void print(Tree root, int s, int dir)
{
    if(root != NULL)
    {
        int i;
        char buf[10];
        sprintf(buf, "|-%d-", root->key);
        int len = strlen(buf);
        for(i = 0; i < len; i++)
        {
            l[s + i] = S;
        }
        if(dir == D)
        {
            l[s] = '|';
        }
        print(root->left, s + len, U);
        
        l[s] = '\0';
        if(root->left == NULL && root->right == NULL)
        {
            buf[len - 1] = '\0';
            printf("%s%s\n", l, buf);
        }
        else
        {
            printf("%s%s|\n", l, buf);
        }
        l[s] = S;
        
        if(dir == U)
        {
            l[s] = '|';
        }
        print(root->right, s + len, D);
        l[s] = S;
    }
}

void printPre(Tree root, int s)
{
    if(root != NULL)
    {
        int i;
        char buf[10];
        sprintf(buf, "%d-", root->key);
        int len = strlen(buf);
        for(i = 0; i < len; i++)
        {
            l[s + i] = S;
        }
        print(root->left, s + len, U);
        
        printf("%s|\n", buf);
        
        print(root->right, s + len, D);
    }
}

int main(void)
{
    int n;
    Tree tree = NULL;
    while(scanf("%d", &n) > 0)
    {
        Tree neo = malloc(sizeof(TNode));
        neo->key = n;
        neo->left = neo->right = NULL;
        tree = insert(tree, neo);
    }
    printPre(tree, 0);
    return 0;
}

 

/*
歷屆試題 危險係數

問題描述
抗日戰爭時期,冀中平原的地道戰曾發揮重要作用。

地道的多個站點間有通道連接,形成了龐大的網絡。但也有隱患,當敵人發現了某個站點後,其它站點間可能因此會失去聯繫。

我們來定義一個危險係數DF(x,y):

對於兩個站點x和y (x != y), 如果能找到一個站點z,當z被敵人破壞後,x和y不連通,那麼我們稱z爲關於x,y的關鍵點。相應的,對於任意一對站點x和y,危險係數DF(x,y)就表示爲這兩點之間的關鍵點個數。

本題的任務是:已知網絡結構,求兩站點之間的危險係數。

輸入格式
輸入數據第一行包含2個整數n(2 <= n <= 1000), m(0 <= m <= 2000),分別代表站點數,通道數;

接下來m行,每行兩個整數 u,v (1 <= u, v <= n; u != v)代表一條通道;

最後1行,兩個數u,v,代表詢問兩點之間的危險係數DF(u, v)。

輸出格式
一個整數,如果詢問的兩點不連通則輸出-1.
樣例輸入
7 6
1 3
2 3
3 4
3 5
4 5
5 6
1 6
樣例輸出
2
*/
#include<stdio.h>
#include<stdlib.h>
struct Node
{
    int data;
    struct Node *pNext;
};
struct Node tab[1001];
int visit[1001]={0};
int way[1001]={0};
int count[1001]={0};
int cnt=0;
void Insert(int n,int x);
void Init(int n);
void dfs(int x,int y,int n);
int fun(int n);
int main()
{
    int x,y,n,m,u,v;
    scanf("%d%d",&n,&m);
    Init(n);
    while(m--)
    {
        scanf("%d%d",&u,&v);
        Insert(u,v);
        Insert(v,u);
    }
    scanf("%d%d",&x,&y);
    dfs(x,y,0);
    int ret=fun(n);
    printf("%d\n",ret);
    return 0;
}
int fun(int n)
{
    int i;
    int ret=0;
    for(i=1;i<=n;i++)
    {
        if(count[i]==cnt)
        {
            ret++;
        }
    }
    return (ret-2);
}
void dfs(int x,int y,int n)
{
    visit[x]=1;
    way[n]=x;
    struct Node *p=&tab[x];
    if(x==y)
    {
        int i;
        cnt++;
        for(i=0;i<=n;i++)
        {
            count[way[i]]++;
        }
        return ;
    }
    while((p=p->pNext)!=NULL)
    {
        if(visit[p->data]!=1)
        {
            dfs(p->data,y,n+1);
            visit[p->data]=0;
        }
    }
}
void Init(int n)
{
    int i;
    for(i=1;i<=n;i++)
    {
        tab[i].data=i;
        tab[i].pNext=NULL;
    }
}

void Insert(int n,int x)
{
    struct Node *p=&tab[n];
    while(p->pNext!=NULL)
    {
        p=p->pNext;
    }
    struct Node *new=(struct Node *)malloc(sizeof(struct Node));
    p->pNext=new;
    new->data=x;
    new->pNext=NULL;
}

 

/*
歷屆試題 網絡尋路

問題描述
X 國的一個網絡使用若干條線路連接若干個節點。節點間的通信是雙向的。某重要數據包,爲了安全起見,必須恰好被轉發兩次到達目的地。該包可能在任意一個節點產生,我們需要知道該網絡中一共有多少種不同的轉發路徑。

源地址和目標地址可以相同,但中間節點必須不同。

如下圖所示的網絡。

圖爲123互連,235互連,2連接4 (直線連接) 


1 -> 2 -> 3 -> 1 是允許的

1 -> 2 -> 1 -> 2 或者 1 -> 2 -> 3 -> 2 都是非法的。

輸入格式
輸入數據的第一行爲兩個整數N M,分別表示節點個數和連接線路的條數(1<=N<=10000; 0<=M<=100000)。

接下去有M行,每行爲兩個整數 u 和 v,表示節點u 和 v 聯通(1<=u,v<=N , u!=v)。

輸入數據保證任意兩點最多隻有一條邊連接,並且沒有自己連自己的邊,即不存在重邊和自環。

輸出格式
輸出一個整數,表示滿足要求的路徑條數。
樣例輸入1
3 3
1 2
2 3
1 3
樣例輸出1
6
樣例輸入2
4 4
1 2
2 3
3 1
1 4
樣例輸出2
10
*/
#include<stdio.h>
#include<string.h>
#define MAXN 10010
#define MAXM 100010
int Du[MAXN],U[MAXM],V[MAXM];
int main()
{
    int n,i,m;
    long long ans=0;
    scanf("%d%d",&n,&m);
    memset(Du,0,sizeof(Du));
    for(i=0;i<m;i++){
        scanf("%d%d",&U[i],&V[i]);
        Du[U[i]]++;
        Du[V[i]]++;
    }
    for(i=0;i<m;i++)if(Du[U[i]]>1&&Du[V[i]]>1)ans+=(Du[U[i]]-1)*(Du[V[i]]-1)*2; 
    printf("%I64d\n",ans);
    return 0;
}

 

/*
歷屆試題 高僧鬥法 

問題描述
  古時喪葬活動中經常請高僧做法事。儀式結束後,有時會有“高僧鬥法”的趣味節目,以舒緩壓抑的氣氛。
  節目大略步驟爲:先用糧食(一般是稻米)在地上“畫”出若干級臺階(表示N級浮屠)。又有若干小和尚隨機地“站”在某個臺階上。最高一級臺階必須站人,其它任意。(如圖1所示)
  兩位參加遊戲的法師分別指揮某個小和尚向上走任意多級的臺階,但會被站在高級臺階上的小和尚阻擋,不能越過。兩個小和尚也不能站在同一臺階,也不能向低級臺階移動。
  兩法師輪流發出指令,最後所有小和尚必然會都擠在高段臺階,再也不能向上移動。輪到哪個法師指揮時無法繼續移動,則遊戲結束,該法師認輸。
  對於已知的臺階數和小和尚的分佈位置,請你計算先發指令的法師該如何決策才能保證勝出。
輸入格式
  輸入數據爲一行用空格分開的N個整數,表示小和尚的位置。臺階序號從1算起,所以最後一個小和尚的位置即是臺階的總數。(N<100, 臺階總數<1000)
輸出格式
  輸出爲一行用空格分開的兩個整數: A B, 表示把A位置的小和尚移動到B位置。若有多個解,輸出A值較小的解,若無解則輸出-1。
樣例輸入
1 5 9
樣例輸出
1 4
樣例輸入
1 5 8 10
樣例輸出
1 3
*/
//參考藍橋杯貼吧 dezhonger
#include <stdio.h>   
int main()
{
    int a[105],b[105],i=0,j,k,count,sum;
    char c;
    while(1)
    {
        scanf("%d%c",&a[i++],&c);
        if(c=='\n')
            break;
    }
    count=i;
    for(i = 0;i < count-1;i++)
        b[i]=a[i+1]-a[i]-1;
    b[count-1]=0;
    sum=b[0];
    for(i = 2;i < count;i = i+2)
        sum^=b[i];
    if(sum == 0)
        printf("-1\n");
    else
    {
        for(i = 0;i < count;i++)
            for(j = 1;j <= b[i];j++)
            {
                b[i] -= j;
                if(i!=0)
                    b[i-1]+=j;
                sum = b[0];
                for(k = 2;k < count;k = k+2)
                    sum ^= b[k];
                if(sum == 0)
                {
                    printf("%d %d\n",a[i],a[i]+j);
                    break;
                }
                b[i] += j;
                if(i != 0)
                    b[i-1] -= j;
            }
    }
    return 0;
}

/*
1 3 5 7 12 14 17 26 38 45 66 100
66 84
*/

 

/*
歷屆試題 格子刷油漆

問題描述
  X國的一段古城牆的頂端可以看成 2*N個格子組成的矩形(如下圖所示),現需要把這些格子刷上保護漆。

    圖爲由2X3個小矩形拼成的大矩形格子,上三個矩形依次爲a,c,e,下三個矩形依次爲b,d,f
    城牆寬度爲2格(即上下兩層矩形),長度未知,此時爲3 

  你可以從任意一個格子刷起,刷完一格,可以移動到和它相鄰的格子(對角相鄰也算數),但不能移動到較遠的格子(因爲油漆未乾不能踩!)
  比如:a d b c e f 就是合格的刷漆順序。
  c e f d a b 是另一種合適的方案。
  當已知 N 時,求總的方案數。當N較大時,結果會迅速增大,請把結果對 1000000007 (十億零七) 取模。
輸入格式
  輸入數據爲一個正整數(不大於1000)
輸出格式
  輸出數據爲一個正整數。
樣例輸入
2
樣例輸出
24
樣例輸入
3
樣例輸出
96
樣例輸入
22
樣例輸出
359635897
*/
#include <stdio.h>  
long long a[1001],b[1001],sum;  
#define NUM 1000000007 
int main()  
{  
    int i,n;  
    scanf("%d",&n);  
    b[1]=1;  
    for (i=2;i<=n;i++)  
        b[i]=(b[i-1]*2%NUM);  
    a[1]=1;a[2]=6;  
    for (i=3;i<=n;i++)  
        a[i]=(2*a[i-1]+b[i]+4*a[i-2])%NUM;  
    sum=4*a[n];  
    for (i=2;i<n;i++)  
        sum=((sum+8*b[n-i]*a[i-1]%NUM)%NUM+(8*a[n-i]*b[i-1])%NUM)%NUM;  
    printf("%I64d\n",sum);  
    return 0;  
}

 

/*
歷屆試題 農場陽光

問題描述
  X星球十分特殊,它的自轉速度與公轉速度相同,所以陽光總是以固定的角度照射。
  最近,X星球爲發展星際旅遊業,把空間位置出租給Y國遊客來曬太陽。每個租位是漂浮在空中的圓盤形彩雲(圓盤與地面平行)。當然,這會遮擋住部分陽光,被遮擋的土地植物無法生長。
  本題的任務是計算某個農場宜於作物生長的土地面積有多大。
輸入格式
  輸入數據的第一行包含兩個整數a, b,表示某農場的長和寬分別是a和b,此時,該農場的範圍是由座標(0, 0, 0), (a, 0, 0), (a, b, 0), (0, b, 0)圍成的矩形區域。
  第二行包含一個實數g,表示陽光照射的角度。簡單起見,我們假設陽光光線是垂直於農場的寬的,此時正好和農場的長的夾角是g度,此時,空間中的一點(x, y, z)在地面的投影點應該是(x + z * ctg(g度), y, 0),其中ctg(g度)表示g度對應的餘切值。
  第三行包含一個非負整數n,表示空中租位個數。
  接下來 n 行,描述每個租位。其中第i行包含4個整數xi, yi, zi, ri,表示第i個租位彩雲的圓心在(xi, yi, zi)位置,圓半徑爲ri。
輸出格式
  要求輸出一個實數,四捨五入保留兩位有效數字,表示農場裏能長莊稼的土地的面積。
樣例輸入
10 10
90.0
1
5 5 10 5
樣例輸出
21.46
樣例輸入
8 8
90.0
1
4 4 10 5
樣例輸出
1.81
樣例輸入
20 10
45.0
2
5 0 5 5
8 6 14 6
樣例輸出
130.15
*/

//該題未解決,如有解答出請給個思路參考下,謝謝

 

/*
歷屆試題 約數倍數選卡片

問題描述
  閒暇時,福爾摩斯和華生玩一個遊戲:
  在N張卡片上寫有N個整數。兩人輪流拿走一張卡片。要求下一個人拿的數字一定是前一個人拿的數字的約數或倍數。例如,某次福爾摩斯拿走的卡片上寫着數字“6”,則接下來華生可以拿的數字包括:
  1,2,3, 6,12,18,24 ....
  當輪到某一方拿卡片時,沒有滿足要求的卡片可選,則該方爲輸方。
  請你利用計算機的優勢計算一下,在已知所有卡片上的數字和可選哪些數字的條件下,怎樣選擇才能保證必勝!
  當選多個數字都可以必勝時,輸出其中最小的數字。如果無論如何都會輸,則輸出-1。
輸入格式
  輸入數據爲2行。第一行是若干空格分開的整數(每個整數介於1~100間),表示當前剩餘的所有卡片。
  第二行也是若干空格分開的整數,表示可以選的數字。當然,第二行的數字必須完全包含在第一行的數字中。
輸出格式
  程序則輸出必勝的招法!!
樣例輸入
2 3 6
3 6
樣例輸出
3
樣例輸入
1 2 2 3 3 4 5
3 4 5
樣例輸出
4
*/
#include <iostream> 
#include <fstream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <climits>
#include <ctime>
#include <cmath>
#include <set>
#include <map>
#include <string>
#include <vector>
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):(-(x)))
#define FOR(i,a,b) for(int i = (a);i<=(b);i++)
#define FORD(i,a,b) for(int i = (a);i>=(b);i--)
#define REP(i,n) for(int i = 0;i<(n);i++)
#define rst(x,k) memset(x,k,sizeof(x))
#define lowbit(x) ((x)&(-(x)))
//#define h(x) (1<<(x))
//#define lson (ind<<1)
//#define rson (ind<<1|1)
#define eps 1e-6
#define INF 140000000
#define maxn 5000
#define mod 1000000007
#define Pi acos(-1.0)
#define link fjksldfjaslkdfjas
using namespace std;
typedef long long LL;
int a[maxn] , b[maxn];
int visit[maxn];
char ss[maxn];
struct node{
int t,nxt;
}edge[maxn << 2];
int headline[maxn] , E , n , tot;
void add(int f,int t){
edge[E].t = t;
edge[E].nxt = headline[f];
headline[f] = E++;
}
bool dfs(int u){
bool ok = true;
visit[u] = true;
for(int i = headline[u];~i;i = edge[i].nxt){
int v = edge[i].t;
if(!visit[v]){
if(dfs(v)){
ok = false;
break;
}
}
}
visit[u] = false;
if(ok == false)return false;
return true;
}
void solve(void){
n = 0; tot = 0;
int len = strlen(ss) , temp = 0;
rst(headline,-1); E = 0; rst(visit,false);
bool finish = true;
REP(i,len){
if(ss[i] <= '9' && ss[i] >= '0'){
temp *= 10;
temp += ss[i] - '0';
finish = false;
}else if(!finish){
finish = true;
n++; a[n] = temp;
temp = 0;
}
}
if(!finish){
n++; a[n] = temp;
finish = true;
temp = 0;
}
gets(ss);
len = strlen(ss);
REP(i,len){
if(ss[i] <= '9' && ss[i] >= '0'){
temp *= 10;
temp += ss[i] - '0';
finish = false;
}else if(!finish){
finish = true;
tot++; b[tot] = temp;
temp = 0;
}
}
if(!finish){
tot++; b[tot] = temp;
finish = true;
temp = 0;
}
sort(a+1,a+n+1);
sort(b+1,b+tot+1);
//FOR(i,1,n)printf("%d ",a[i]);printf("\n");
//FOR(i,1,tot)printf("%d ",b[i]);printf("\n");
FOR(i,1,n){
FOR(j,i+1,n){
if(a[i] % a[j] == 0 || a[j] % a[i] == 0){
add(i,j); add(j,i);
}
}
}
FOR(i,1,tot){
FOR(j,1,n){
if(b[i] == a[j]){
if(dfs(j)){
printf("%d\n",a[j]);
return;
}
break;
}
}
}
printf("-1\n");
}
int main(void){
while(gets(ss)) solve();
return 0;
}

 

/*
歷屆試題 車輪軸跡

問題描述
  棟棟每天騎自行車回家需要經過一條狹長的林蔭道。道路由於年久失修,變得非常不平整。雖然棟棟每次都很顛簸,但他仍把騎車經過林蔭道當成一種樂趣。
  由於顛簸,棟棟騎車回家的路徑是一條上下起伏的曲線,棟棟想知道,他回家的這條曲線的長度究竟是多長呢?更準確的,棟棟想知道從林蔭道的起點到林蔭道的終點,他的車前輪的軸(圓心)經過的路徑的長度。
  棟棟對路面進行了測量。他把道路簡化成一條條長短不等的直線段,這些直線段首尾相連,且位於同一平面內。並在該平面內建立了一個直角座標系,把所有線段的端點座標都計算好。
  假設棟棟的自行車在行進的過程中前輪一直是貼着路面前進的。
    
    圖片請百度

  上圖給出了一個簡單的路面的例子,其中藍色實線爲路面,紅色虛線爲車輪軸經過的路徑。在這個例子中,棟棟的前輪軸從A點出發,水平走到B點,然後繞着地面的F點到C點(繞出一個圓弧),再沿直線下坡到D點,最後水平走到E點,在這個圖中地面的座標依次爲:(0, 0), (2, 0), (4, -1), (6, -1),前輪半徑爲1.50,前輪軸前進的距離依次爲:
  AB=2.0000;弧長BC=0.6955;CD=1.8820;DE=1.6459。
  總長度爲6.2233。

  下圖給出了一個較爲複雜的路面的例子,在這個例子中,車輪在第一個下坡還沒下完時(D點)就開始上坡了,之後在坡的頂點要從E繞一個較大的圓弧到F點。這個圖中前輪的半徑爲1,每一段的長度依次爲:
  AB=3.0000;弧長BC=0.9828;CD=1.1913;DE=2.6848;弧長EF=2.6224; FG=2.4415;GH=2.2792。
  總長度爲15.2021。
    
    圖片請百度
    
  現在給出了車輪的半徑和路面的描述,請求出車輪軸軌跡的總長度。
輸入格式
  輸入的第一行包含一個整數n和一個實數r,用一個空格分隔,表示描述路面的座標點數和車輪的半徑。
  接下來n行,每個包含兩個實數,其中第i行的兩個實數x[i], y[i]表示描述路面的第i個點的座標。
  路面定義爲所有路面座標點順次連接起來的折線。給定的路面的一定滿足以下性質:

  *第一個座標點一定是(0, 0);
  *第一個點和第二個點的縱座標相同;
  *倒數第一個點和倒數第二個點的縱座標相同;
  *第一個點和第二個點的距離不少於車輪半徑;
  *倒數第一個點和倒數第二個點的的距離不少於車輪半徑;
  *後一個座標點的橫座標大於前一個座標點的橫座標,即對於所有的i,x[i+1]>x[i]。
輸出格式
  輸出一個實數,四捨五入保留兩個小數,表示車輪軸經過的總長度。
  你的結果必須和參考答案一模一樣才能得分。數據保證答案精確值的小數點後第三位不是4或5。
樣例輸入
4 1.50
0.00 0.00
2.00 0.00
4.00 -1.00
6.00 -1.00
樣例輸出
6.22
樣例說明
  這個樣例對應第一個圖。
樣例輸入
6 1.00
0.00 0.00
3.00 0.00
5.00 -3.00
6.00 2.00
7.00 -1.00
10.00 -1.00
樣例輸出
15.20
樣例說明
  這個樣例對應第二個圖
數據規模和約定
  對於20%的數據,n=4;
  對於40%的數據,n≤10;
  對於100%的數據,4≤n≤100,0.5≤r≤20.0,x[i] ≤2000.0,-2000.0≤y[i] ≤2000.0。

*/
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm>
 
 
using namespace std;
 
const int MAXN = 10000;
const double PI = atan(1.0) * 4;
const double EPS = 1e-10;
 
class Point {
public:
    double x, y;
    Point() {}
    Point(double x, double y) : x(x), y(y) {}
    Point operator - (const Point &r) const { return Point(x-r.x, y-r.y); }
    Point operator + (const Point &r) const { return Point(x+r.x, y+r.y); }
    Point &operator += (const Point &r) { x += r.x; y += r.y; return *this; }
    Point &operator *= (double m) { x *= m; y *= m; return *this; }
    Point pOfRotate(double angle) const {
        double cosA = cos(angle);
        double sinA = sin(angle);
        return Point(cosA*x-sinA*y, sinA*x+cosA*y);
    }
    Point pOfRotate90() const { return Point(-y, x); }
    double length() const { return sqrt(x*x+y*y); }
    Point pOfNormal() const {
        double len = length();
        return Point(x/len, y/len);
    }
    double angle() const { return atan2(y, x); }
};
 
ostream & operator <<(ostream &os, const Point &v)
{
    os << "(" << v.x << "," << v.y << ")";
    return os;
}
 
class Segment;
class Circle;
 
class Seg {
public:
    virtual double getLeft() const = 0;
    virtual double getRight() const = 0;
    virtual double getY(double x) const = 0;
    virtual double getLength(double x1, double x2) const = 0;
    virtual void intersect(Seg *r) const = 0;
    virtual void intersect(const Segment &v) const = 0;
    virtual void intersect(const Circle &v) const = 0;
    bool contains(double x) const { return x>=getLeft() && x<=getRight(); }
    virtual void acceptPrint(ostream &os) const = 0;
};
 
ostream & operator <<(ostream &os, const Seg &v)
{
    v.acceptPrint(os);
    return os;
}
 
Point intersectRet[4];
int tIntersectRet;
 
class Segment : public Seg {
public:
    Point a, b;
    Segment &moveLeft(double dis)
    {
        Point tmp = ((b-a).pOfRotate90().pOfNormal() *= dis);
        a += tmp;
        b += tmp;
        return *this;
    }
    virtual double getLeft() const { return a.x; }
    virtual double getRight() const { return b.x; }
    virtual double getY(double x) const {
        return (x-a.x)*(b.y-a.y)/(b.x-a.x)+a.y;
    }
    virtual double getLength(double x1, double x2) const {
        return (x2-x1) * (b-a).length() / (b.x-a.x);
    }
    virtual void intersect(Seg *r) const {
        r->intersect(*this);
    }
    virtual void intersect(const Segment &v) const {
        tIntersectRet = 0;
        double ang = (b-a).angle();
        Point c = (v.a-a).pOfRotate(-ang);
        Point d = (v.b-a).pOfRotate(-ang);
        // Bug
        //double di = b.length();
        double di = (b-a).length();
        if (!((c.y>0&&d.y<0) || (c.y<0&&d.y>0)))
            return ;
        double x = (d.x-c.x) * (-c.y) / (d.y-c.y) + c.x;
        if (x<0 || x>di)
            return ;
        Point ret = Point(x,0).pOfRotate(ang)+a;
        intersectRet[tIntersectRet++] = ret;
    }
    virtual void intersect(const Circle &v) const;
    virtual void acceptPrint(ostream &os) const {
        os << a << "-" << b;
    }
};
 
class Circle : public Seg {
public:
    Point c;
    double r;
    virtual double getLeft() const { return c.x - r; }
    virtual double getRight() const { return c.x + r; }
    virtual double getY(double x) const {
        double y2 = r * r - (c.x - x) * (c.x - x);
        if (y2<0) y2 = 0;
        return c.y + sqrt(y2);
    }
    virtual double getLength(double x1, double x2) const {
        x1 -= c.x; x2 -= c.x;
        double a1 = Point(x1, sqrt(abs(r*r-x1*x1))).angle(), a2 = Point(x2, sqrt(abs(r*r-x2*x2))).angle();
        return (a1-a2) * r;
    }
    virtual void intersect(Seg *r) const {
        r->intersect(*this);
    }
    virtual void intersect(const Segment &v) const {
        tIntersectRet = 0;
        Point a = v.a - c;
        Point b = v.b - c;
        double ang = (b-a).angle();
        Point nA = a.pOfRotate(-ang);
        Point nB = b.pOfRotate(-ang);
        double y = nA.y;
        if (y>r || y<-r)
            return ;
        double x = sqrt(r*r - y*y);
        if (x>=nA.x && x<=nB.x)
            intersectRet[tIntersectRet++] = Point(x, y).pOfRotate(ang) + c;
        if (-x>=nA.x && -x<=nB.x)
            intersectRet[tIntersectRet++] = Point(-x, y).pOfRotate(ang) + c;
    }
    virtual void intersect(const Circle &v) const {
        tIntersectRet = 0;
        Point p = v.c - c;
        double d = p.length();
        if (d > r + v.r || d==0)
            return ;
        double x = (r*r - v.r*v.r + d*d) / (2*d);
        if (x <= r)
        {
            double y = sqrt(abs(r*r - x*x));
            double ang = p.angle();
            intersectRet[tIntersectRet++] = Point(x,y).pOfRotate(ang) + c;
            intersectRet[tIntersectRet++] = Point(x,-y).pOfRotate(ang) + c;
        }
    }
    virtual void acceptPrint(ostream &os) const {
        os << c << "," << r;
    }
};
 
void Segment::intersect(const Circle &v) const {
    v.intersect(*this);
}
 
int n;
Point inps[MAXN];
vector<Seg *> segs;
vector<double> spes;
double radius = 1;
 
void input()
{
    scanf("%d%lf", &n, &radius);
    for (int i = 0; i < n; ++i)
    {
        double x, y;
        scanf("%lf%lf", &x, &y);
        inps[i] = Point(x, y);
    }
}
 
void process()
{
    segs.clear();
    spes.clear();
    for (int i = 1; i + 1 < n; ++i)
    {
        Circle *tmp = new Circle;
        tmp->c = inps[i];
        tmp->r = radius;
        segs.push_back(tmp);
    }
    for (int i = 0; i + 1 < n; ++i)
    {
        Segment *tmp = new Segment;
        tmp->a = inps[i];
        tmp->b = inps[i+1];
        tmp->moveLeft(radius);
        segs.push_back(tmp);
    }
    for (int i = 0; i < (int)segs.size(); ++i)
    {
        spes.push_back(segs[i]->getLeft());
        spes.push_back(segs[i]->getRight());
    }
    for (int i = 0; i < (int)segs.size(); ++i)
    {
        for (int j = i+1; j < (int)segs.size(); ++j)
        {
            segs[i]->intersect(segs[j]);
            if (tIntersectRet > 0)
            {
                for (int id = 0; id < tIntersectRet; ++id)
                {
                    //cout << *segs[i] << " " << *segs[j] << " : " << intersectRet[id] << endl;
                    spes.push_back(intersectRet[id].x);
                }
            }
        }
    }
    sort(spes.begin(), spes.end());
    double pre = spes[0];
    const double NONE = 1e30;
    double preEnd = NONE;
    double totalLen = 0;
    for (int i = 1; i < (int)spes.size(); ++i)
    {
        if (spes[i]-pre < EPS)
            continue;
        double cur = (pre+spes[i]) / 2;
        //cout << "Processing " << cur << "  from " << pre << " to " << spes[i] << endl;
        if (cur>=inps[0].x && cur<=inps[n-1].x)
        {
            double MY = -NONE;
            int who;
            for (int j = 0; j < (int)segs.size(); ++j)
            {
                if (!segs[j]->contains(cur))
                    continue;
                double y = segs[j]->getY(cur);
                if (y > MY)
                {
                    MY = y;
                    who = j;
                }
            }
            if (preEnd != NONE)
            {
                double LY = segs[who]->getY(pre);
                //cout << "Drop info " << *segs[who] << " " << "[" << pre << "]" << endl;
                totalLen += abs(preEnd-LY);
                //cout << "Pre drop = " << abs(preEnd-LY) << "  from " << preEnd << " to " << LY << endl;
            }
            double len = segs[who]->getLength(pre, spes[i]);
            if (len < 0)
                printf("Error!\n");
            //cout << "Curlen = " << len << " from " << pre << " to " << spes[i] << endl;
            totalLen += len;
            preEnd = segs[who]->getY(spes[i]);
        }
        pre = spes[i];
    }
    printf("%0.2lf\n", totalLen);
    for (int i = 0; i < (int)segs.size(); ++i)
        delete segs[i];
    segs.clear();
}
 
int main()
{
    input();
    process();
    return 0;
}

 

/*
歷屆試題 九宮重排

問題描述
  如下面第一個圖的九宮格中,放着 1~8 的數字卡片,還有一個格子空着。與空格子相鄰的格子中的卡片可以移動到空格中。經過若干次移動,可以形成第二個圖所示的局面。
    
    圖爲2個9宮格,第一個爲123,456,78空格。第二個爲123,空格46,758。 
    
  我們把第一個圖的局面記爲:12345678.
  把第二個圖的局面記爲:123.46758
  顯然是按從上到下,從左到右的順序記錄數字,空格記爲句點。
  本題目的任務是已知九宮的初態和終態,求最少經過多少步的移動可以到達。如果無論多少步都無法到達,則輸出-1。
輸入格式
  輸入第一行包含九宮的初態,第二行包含九宮的終態。
輸出格式
  輸出最少的步數,如果不存在方案,則輸出-1。
樣例輸入
12345678.
123.46758
樣例輸出
3
樣例輸入
13524678.
46758123.
樣例輸出
22
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct _Node
{
    char tab[3][3];
    int x,y;
    int no;
}Node,*pNode;
int vx[4]={-1,1,0,0};
int vy[4]={0,0,-1,1};
Node res[400000];
int front=0,rear=0;
int vis[4000000],fact[9]; 

void input(pNode start);
void bfs(pNode start,pNode end);
void init_lookup_table();
int try_to_insert(int s);
int main()
{
    Node start,end;
    input(&start);
    input(&end);
    bfs(&start,&end);
    printf("-1\n");
    return 0; 
}
void input(pNode start)
{
    int i,j;
    for(i=0;i<3;i++)
    {
        for(j=0;j<3;j++)
        {
            scanf("%c",&( (start->tab)[i][j] ));
            if((start->tab)[i][j]=='.')
            {
                start->x = i;
                start->y = j;
            }
        }
    }
    start->no = 0;
    getchar();
}
void bfs(pNode start,pNode end)
{
    int i,j;
    char ch;
    pNode tmp;
    init_lookup_table();
    memcpy(&res[rear],start,sizeof(res[rear]));
    try_to_insert(rear); 
    rear++;
    while(front!=rear)
    {
        //printf("%d  ",rear);
        tmp = &res[front];
        if(memcmp(tmp->tab,end->tab,sizeof(end->tab))==0)
        {
            printf("%d\n",tmp->no);
            exit(0);
        }
        int no = tmp->no;
        for(i=0;i<4;i++)
        {
            int xx = tmp->x+vx[i];
            int yy = tmp->y+vy[i];
            if(xx>=0 && xx<3 && yy>=0 && yy<3)
            {
                pNode p = &res[rear];
                memcpy(p,tmp,sizeof(res[front]));
                p->tab[tmp->x][tmp->y] = p->tab[xx][yy];
                p->tab[xx][yy] = tmp->tab[tmp->x][tmp->y];
                p->no = no+1;
                p->x = xx;
                p->y = yy;
                if(try_to_insert(rear))
                {
                    rear++;
                }
            }
        }
        front++;
        //printf("%d  ",rear);
    }
}

void init_lookup_table()
{
    int i;
    fact[0] = 1;
    for(i=1;i<9;i++)
    {
        fact[i] = fact[i-1]*i;
    }
}

int try_to_insert(int s)
{
    int i,j;
    int code = 0;
    for(i=0;i<9;i++)
    {
        int cnt = 0;
        for(j=i+1;j<9;j++)
        {
            if(res[s].tab[j/3][j%3] < res[s].tab[i/3][i%3])
            {
                cnt++;
            }
            code += fact[8-i]*cnt;
        }
    }
    if(vis[code])
    {
        return 0;
    }
    return vis[code] = 1;
}

 

/*
歷屆試題 公式求值

問題描述
  輸入n, m, k,輸出下面公式的值。

    圖片請百度 

  其中C_n^m是組合數,表示在n個人的集合中選出m個人組成一個集合的方案數。組合數的計算公式如下。
    
    圖片請百度 
    
輸入格式
  輸入的第一行包含一個整數n;第二行包含一個整數m,第三行包含一個整數k。
輸出格式
  計算上面公式的值,由於答案非常大,請輸出這個值除以999101的餘數。
樣例輸入
3
1
3
樣例輸出
162
樣例輸入
20
10
10
樣例輸出
359316
數據規模和約定
  對於10%的數據,n≤10,k≤3;
  對於20%的數據,n≤20,k≤3;
  對於30%的數據,n≤1000,k≤5;
  對於40%的數據,n≤10^7,k≤10;
  對於60%的數據,n≤10^15,k ≤100;
  對於70%的數據,n≤10^100,k≤200;
  對於80%的數據,n≤10^500,k ≤500;
  對於100%的數據,n在十進制下不超過1000位,即1≤n<10^1000,1≤k≤1000,同時0≤m≤n,k≤n。
提示
  999101是一個質數;
  當n位數比較多時,絕大多數情況下答案都是0,但評測的時候會選取一些答案不是0的數據;
*/

//該題未解決

 

 

 

GoToNextPart

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章