1. 程式人生 > 實用技巧 >2020年HZNU天梯訓練賽 Round 3

2020年HZNU天梯訓練賽 Round 3

2020年HZNU天梯訓練賽 Round 3

時間:2020.7.17 22 180

完成情況:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

√ 當場做出來 ※做了一半來 ✘補題補出來

7-1 到底有多二 (15分)

一個整數“犯二的程度”定義為該數字中包含2的個數與其位數的比值。如果這個數是負數,則程度增加0.5倍;如果還是個偶數,則再增加1倍。例如數字-13142223336是個11位數,其中有3個2,並且是負數,也是偶數,則它的犯二程度計算為:3/11×1.5×2×100%,約為81.82%。本題就請你計算一個給定整數到底有多二。

輸入格式:

輸入第一行給出一個不超過50位的整數N

輸出格式:

在一行中輸出N犯二的程度,保留小數點後兩位。

輸入樣例:

-13142223336

輸出樣例:

81.82%
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long LL;

int main()
{
	char s[55];
	int cnt=0,num=0,begin=0;
	cin>>s;
	double p=1;
	if(s[0]=='-'){p*=1.5;begin=1;}
	if((s[strlen(s)-1]-'0')%2==0)p*=2;
	
	for(int i=begin;i<strlen(s);i++)
	{
		if((s[i]-'0')%10==2)cnt++;
		num++;
	}
	//cout<<cnt<<"***"<<num<<endl;
	double ans=(double)cnt/(double)num*p*100;
	printf("%.2lf%%",ans);
    return 0;
}

7-2 大笨鐘 (10分)

微博上有個自稱“大笨鐘V”的傢伙,每天敲鐘催促碼農們愛惜身體早點睡覺。不過由於笨鍾自己作息也不是很規律,所以敲鐘並不定時。一般敲鐘的點數是根據敲鐘時間而定的,如果正好在某個整點敲,那麼“當”數就等於那個整點數;如果過了整點,就敲下一個整點數。另外,雖然一天有24小時,鍾卻是隻在後半天敲1~12下。例如在23:00敲鐘,就是“噹噹噹噹噹噹噹噹噹噹噹”,而到了23:01就會是“噹噹噹噹噹噹噹噹噹噹噹噹”。在午夜00:00到中午12:00期間(端點時間包括在內),笨鍾是不敲的。

下面就請你寫個程式,根據當前時間替大笨鐘敲鍾。

輸入格式:

輸入第一行按照hh:mm的格式給出當前時間。其中hh

是小時,在00到23之間;mm是分鐘,在00到59之間。

輸出格式:

根據當前時間替大笨鐘敲鍾,即在一行中輸出相應數量個Dang。如果不是敲鐘期,則輸出:

Only hh:mm.  Too early to Dang.

其中hh:mm是輸入的時間。

輸入樣例1:

19:05

輸出樣例1:

DangDangDangDangDangDangDangDang
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int main()
{
    int a,b;
    scanf("%d:%d",&a,&b);
    if(a<12||(a==12&&b==00))
	{
        if(a<10&&b>10)printf("Only 0%d:%d.  Too early to Dang.\n",a,b);
        if(a<10&&b<10)printf("Only 0%d:0%d.  Too early to Dang.\n",a,b);
        if(a>10&&b<10)printf("Only %d:0%d.  Too early to Dang.\n",a,b);
    	if(a>10&&b>10)printf("Only %d:%d.  Too early to Dang.\n",a,b);
    }
    else
    {
        int x;
        if(b==00) {for(int i=0;i<a-12;i++)cout<<"Dang";}
        else {for(int i=0;i<a-11;i++)cout<<"Dang";}
    }
    return 0;
}

7-3 誰先倒 (15分)

划拳是古老中國酒文化的一個有趣的組成部分。酒桌上兩人划拳的方法為:每人口中喊出一個數字,同時用手比劃出一個數字。如果誰比劃出的數字正好等於兩人喊出的數字之和,誰就輸了,輸家罰一杯酒。兩人同贏或兩人同輸則繼續下一輪,直到唯一的贏家出現。

下面給出甲、乙兩人的酒量(最多能喝多少杯不倒)和划拳記錄,請你判斷兩個人誰先倒。

輸入格式:

輸入第一行先後給出甲、乙兩人的酒量(不超過100的非負整數),以空格分隔。下一行給出一個正整數N(≤100),隨後N行,每行給出一輪划拳的記錄,格式為:

甲喊 甲劃 乙喊 乙劃

其中是喊出的數字,是劃出的數字,均為不超過100的正整數(兩隻手一起劃)。

輸出格式:

在第一行中輸出先倒下的那個人:A代表甲,B代表乙。第二行中輸出沒倒的那個人喝了多少杯。題目保證有一個人倒下。注意程式處理到有人倒下就終止,後面的資料不必處理。

輸入樣例:

1 1
6
8 10 9 12
5 10 5 10
3 8 5 12
12 18 1 13
4 16 12 15
15 1 1 16

輸出樣例:

A
1
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long LL;

int main()
{
	int a,b,n,x,y,z,w,aa,bb;
	cin>>a>>b>>n;
	aa=a;bb=b;
	while(n--)
	{
		cin>>x>>y>>z>>w;
		if(x+z==y&&x+z!=w)a--;
		if(x+z==w&&x+z!=y)b--;
		if(a==-1){cout<<"A"<<endl<<bb-b;break;}
		if(b==-1){cout<<"B"<<endl<<aa-a;break;}
	}

    return 0;
}

7-4 帥到沒朋友 (20分)

當芸芸眾生忙著在朋友圈中發照片的時候,總有一些人因為太帥而沒有朋友。本題就要求你找出那些帥到沒有朋友的人。

輸入格式:

輸入第一行給出一個正整數N(≤100),是已知朋友圈的個數;隨後N行,每行首先給出一個正整數K(≤1000),為朋友圈中的人數,然後列出一個朋友圈內的所有人——為方便起見,每人對應一個ID號,為5位數字(從00000到99999),ID間以空格分隔;之後給出一個正整數M(≤10000),為待查詢的人數;隨後一行中列出M個待查詢的ID,以空格分隔。

注意:沒有朋友的人可以是根本沒安裝“朋友圈”,也可以是隻有自己一個人在朋友圈的人。雖然有個別自戀狂會自己把自己反覆加進朋友圈,但題目保證所有K超過1的朋友圈裡都至少有2個不同的人。

輸出格式:

按輸入的順序輸出那些帥到沒朋友的人。ID間用1個空格分隔,行的首尾不得有多餘空格。如果沒有人太帥,則輸出No one is handsome

注意:同一個人可以被查詢多次,但只輸出一次。

輸入樣例1:

3
3 11111 22222 55555
2 33333 44444
4 55555 66666 99999 77777
8
55555 44444 10000 88888 22222 11111 23333 88888

輸出樣例1:

10000 88888 23333

輸入樣例2:

3
3 11111 22222 55555
2 33333 44444
4 55555 66666 99999 77777
4
55555 44444 22222 11111

輸出樣例2:

No one is handsome
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long LL;
int a[100000]={0};    

int main()
{
  	int n,k,x,m,sum=0;
    cin>>n;   
    for(int i=1;i<=n;i++)    
    {    
        cin>>k;    
        for(int j=1;j<=k;j++)    
        {    
            cin>>x;    
            if(k!=1) a[x]+=k-1;   
        }    
    }    
    cin>>m ;  
    for(int i=1;i<=m;i++)    
    {    
        cin>>x;     
        if(a[x]==0)    
        {    
            if(sum!=0) cout<<" ";    
            printf("%05d",x);    
            a[x]=-1; 
            sum++;    
        }    
    }     
    if(sum==0)  cout<<"No one is handsome" <<endl;    
    return 0;
}

7-5 重要的話說三遍 (5分)

這道超級簡單的題目沒有任何輸入。

你只需要把這句很重要的話 —— “I'm gonna WIN!”——連續輸出三遍就可以了。

注意每遍佔一行,除了每行的回車不能有任何多餘字元。

I'm gonna WIN!
I'm gonna WIN!
I'm gonna WIN!

7-6 奇偶分家 (10分)

給定N個正整數,請統計奇數和偶數各有多少個?

輸入格式:

輸入第一行給出一個正整N(≤1000);第2行給出N個非負整數,以空格分隔。

輸出格式:

在一行中先後輸出奇數的個數、偶數的個數。中間以1個空格分隔。

輸入樣例:

9
88 74 101 26 15 0 34 22 77

輸出樣例:

3 6
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long LL;

int main()
{
	int n,x,o=0,j=0;
	cin>>n;
	while(n--)
	{	
		cin>>x;
		if(x%2==0)	o++;
		else	j++;
		
	} 
   	cout<<j<<" "<<o;
    return 0;
}

7-7 輸出GPLT (20分)

給定一個長度不超過10000的、僅由英文字母構成的字串。請將字元重新調整順序,按GPLTGPLT....這樣的順序輸出,並忽略其它字元。當然,四種字元(不區分大小寫)的個數不一定是一樣多的,若某種字元已經輸出完,則餘下的字元仍按GPLT的順序列印,直到所有字元都被輸出。

輸入格式:

輸入在一行中給出一個長度不超過10000的、僅由英文字母構成的非空字串。

輸出格式:

在一行中按題目要求輸出排序後的字串。題目保證輸出非空。

輸入樣例:

pcTclnGloRgLrtLhgljkLhGFauPewSKgt

輸出樣例:

GPLTGPLTGLTGLGLL
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long LL;

int main()
{
	string s;
    cin>>s;
    int g=0,p=0,l=0,t=0;
    for(int i=0;i<s.size();i++)
    {
        if(s[i]=='G'||s[i]=='g')g++;
    	if(s[i]=='P'||s[i]=='p')p++;
    	if(s[i]=='L'||s[i]=='l')l++;
        if(s[i]=='T'||s[i]=='t')t++;
    }
    while(g||p||l||t)
    {
        if(g){cout<<"G";g--;}
        if(p){cout<<"P";p--;}
        if(l){cout<<"L";l--;}
        if(t){cout<<"T";t--;}
    }
    return 0;
}

7-8 後天 (5分)

如果今天是星期三,後天就是星期五;如果今天是星期六,後天就是星期一。我們用數字1到7對應星期一到星期日。給定某一天,請你輸出那天的“後天”是星期幾。

輸入格式:

輸入第一行給出一個正整數D(1 ≤ D ≤ 7),代表星期裡的某一天。

輸出格式:

在一行中輸出D天的後天是星期幾。

輸入樣例:

3

輸出樣例:

5
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long LL;

int main()
{
	int d;
	cin>>d;
	if(d+2>7)
		cout<<d+2-7;
	else cout<<d+2;
    return 0;
}

7-9 搶紅包 (25分)

沒有人沒搶過紅包吧…… 這裡給出N個人之間互相發紅包、搶紅包的記錄,請你統計一下他們搶紅包的收穫。

輸入格式:

輸入第一行給出一個正整數N(≤104),即參與發紅包和搶紅包的總人數,則這些人從1到N編號。隨後N行,第i行給出編號為i的人發紅包的記錄,格式如下:

K**N1P1⋯NKP**K

其中K(0≤K≤20)是發出去的紅包個數,N**i是搶到紅包的人的編號,P**i(>0)是其搶到的紅包金額(以分為單位)。注意:對於同一個人發出的紅包,每人最多隻能搶1次,不能重複搶。

輸出格式:

按照收入金額從高到低的遞減順序輸出每個人的編號和收入金額(以元為單位,輸出小數點後2位)。每個人的資訊佔一行,兩數字間有1個空格。如果收入金額有並列,則按搶到紅包的個數遞減輸出;如果還有並列,則按個人編號遞增輸出。

輸入樣例:

10
3 2 22 10 58 8 125
5 1 345 3 211 5 233 7 13 8 101
1 7 8800
2 1 1000 2 1000
2 4 250 10 320
6 5 11 9 22 8 33 7 44 10 55 4 2
1 3 8800
2 1 23 2 123
1 8 250
4 2 121 4 516 7 112 9 10

輸出樣例:

1 11.63
2 3.63
8 3.63
3 2.11
7 1.69
6 -1.67
9 -2.18
10 -3.26
5 -3.26
4 -12.32
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long LL;
//int p[10005]={0};    
struct node
{
	int id,num, v;
}p[10000];
bool cmp(struct node a,struct node b)
{
	if(a.v!=b.v)			return a.v>b.v;
	else if(a.num!=b.num)	return a.num>b.num;	
	else if(a.id!=b.id)		return a.id<b.id;	
}
int main()
{
  	int n,k,x,y,sum=0;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		sum=0;
		p[i].id=i;
		cin>>k;
		for(int j=1;j<=k;j++)
		{
			cin>>x>>y;
			p[x].v+=y;
			p[x].num++; 
			sum=sum+y;
		}
		p[i].v-=sum;
	} 

	sort(p+1,p+n+1,cmp);
	for(int i=1;i<=n;i++)	printf("%d %.2lf\n",p[i].id,(double)p[i].v/100);
	return 0;

}

7-10 排座位 (25分)

佈置宴席最微妙的事情,就是給前來參宴的各位賓客安排座位。無論如何,總不能把兩個死對頭排到同一張宴會桌旁!這個艱鉅任務現在就交給你,對任何一對客人,請編寫程式告訴主人他們是否能被安排同席。

輸入格式:

輸入第一行給出3個正整數:N(≤100),即前來參宴的賓客總人數,則這些人從1到N編號;M為已知兩兩賓客之間的關係數;K為查詢的條數。隨後M行,每行給出一對賓客之間的關係,格式為:賓客1 賓客2 關係,其中關係為1表示是朋友,-1表示是死對頭。注意兩個人不可能既是朋友又是敵人。最後K行,每行給出一對需要查詢的賓客編號。

這裡假設朋友的朋友也是朋友。但敵人的敵人並不一定就是朋友,朋友的敵人也不一定是敵人。只有單純直接的敵對關係才是絕對不能同席的。

輸出格式:

對每個查詢輸出一行結果:如果兩位賓客之間是朋友,且沒有敵對關係,則輸出No problem;如果他們之間並不是朋友,但也不敵對,則輸出OK;如果他們之間有敵對,然而也有共同的朋友,則輸出OK but...;如果他們之間只有敵對關係,則輸出No way

輸入樣例:

7 8 4
5 6 1
2 7 -1
1 3 1
3 4 1
6 7 -1
1 2 1
1 4 1
2 3 -1
3 4
5 7
2 3
7 2

輸出樣例:

No problem
OK
OK but...
No way
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long LL;
//int p[10005]={0};  
int a[101][101],b[101];  
/*//並查集板子 
int find(int x)
{
   //while(x!=pre[x])  //如果該結點的父結點不是它自身
    //x=pre[x];  //那麼就繼續找它的父結點的父結點
  return x==pre[x]?x:find(pre[x]);
}
//查詢函式:用於查詢結點的父結點。
void Union(int x,int y)
{
  int fx=find(x);  //找到x的根結點
  int fy=find(y);  //找到y的根結點
  if(fx!=fy)  //如果x和y的根結點不相同(x和y不屬於同一個聯通分支)
    pre[fx]=fy; //就把x的根結點的父結點改為y的根結點
}//合併函式 
*/
int find(int x)
{
    return b[x]==x?x:b[x]=find(b[x]);
}
int main()
{
    int n,m,k,x,y,z,p,q;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)b[i]=i;
    for(int i=0;i<m;i++)
    {
        cin>>x>>y>>z;
        if(z==-1) a[x][y]=a[y][x]=1;
        else 
		{
            int x1=find(x);//查詢 
            int y1=find(y);
            if(x1!=y1) b[x1]=y1;//合併
        }
    }
    for(int i=0;i<k;i++)
    {
        cin>>p>>q;
        int p1=find(p);
        int q1=find(q);
        if(q1==p1&&!a[p][q]) printf("No problem\n");
        else if(q1==p1&&a[p][q]) printf("OK but...\n");
        else if(q1!=p1&&!a[p][q]) printf("OK\n");
        else if(q1!=p1&&a[p][q]) printf("No way\n");
    }
    return 0;
}

7-11 玩轉二叉樹 (25分)

給定一棵二叉樹的中序遍歷和前序遍歷,請你先將樹做個鏡面反轉,再輸出反轉後的層序遍歷的序列。所謂鏡面反轉,是指將所有非葉結點的左右孩子對換。這裡假設鍵值都是互不相等的正整數。

輸入格式:

輸入第一行給出一個正整數N(≤30),是二叉樹中結點的個數。第二行給出其中序遍歷序列。第三行給出其前序遍歷序列。數字間以空格分隔。

輸出格式:

在一行中輸出該樹反轉後的層序遍歷的序列。數字間以1個空格分隔,行首尾不得有多餘空格。

輸入樣例:

7
1 2 3 4 5 6 7
4 1 3 2 6 5 7

輸出樣例:

4 6 1 7 5 3 2

7-12 關於堆的判斷 (25分)

將一系列給定數字順序插入一個初始為空的小頂堆H[]。隨後判斷一系列相關命題是否為真。命題分下列幾種:

  • x is the rootx是根結點;
  • x and y are siblingsxy是兄弟結點;
  • x is the parent of yxy的父結點;
  • x is a child of yxy的一個子結點。

輸入格式:

每組測試第1行包含2個正整數N(≤ 1000)和M(≤ 20),分別是插入元素的個數、以及需要判斷的命題數。下一行給出區間[−10000,10000]內的N個要被插入一個初始為空的小頂堆的整數。之後M行,每行給出一個命題。題目保證命題中的結點鍵值都是存在的。

輸出格式:

對輸入的每個命題,如果其為真,則在一行中輸出T,否則輸出F

輸入樣例:

5 4
46 23 26 24 10
24 is the root
26 and 23 are siblings
46 is the parent of 23
23 is a child of 10

輸出樣例:

F
T
F
T

7-13 天梯地圖 (30分)

本題要求你實現一個天梯賽專屬線上地圖,隊員輸入自己學校所在地和賽場地點後,該地圖應該推薦兩條路線:一條是最快到達路線;一條是最短距離的路線。題目保證對任意的查詢請求,地圖上都至少存在一條可達路線。

輸入格式:

輸入在第一行給出兩個正整數N(2 ≤ N ≤ 500)和M,分別為地圖中所有標記地點的個數和連線地點的道路條數。隨後M行,每行按如下格式給出一條道路的資訊:

V1 V2 one-way length time

其中V1V2是道路的兩個端點的編號(從0到N-1);如果該道路是從V1V2的單行線,則one-way為1,否則為0;length是道路的長度;time是通過該路所需要的時間。最後給出一對起點和終點的編號。

輸出格式:

首先按下列格式輸出最快到達的時間T和用節點編號表示的路線:

Time = T: 起點 => 節點1 => ... => 終點

然後在下一行按下列格式輸出最短距離D和用節點編號表示的路線:

Distance = D: 起點 => 節點1 => ... => 終點

如果最快到達路線不唯一,則輸出幾條最快路線中最短的那條,題目保證這條路線是唯一的。而如果最短距離的路線不唯一,則輸出途徑節點數最少的那條,題目保證這條路線是唯一的。

如果這兩條路線是完全一樣的,則按下列格式輸出:

Time = T; Distance = D: 起點 => 節點1 => ... => 終點

輸入樣例1:

10 15
0 1 0 1 1
8 0 0 1 1
4 8 1 1 1
5 4 0 2 3
5 9 1 1 4
0 6 0 1 1
7 3 1 1 2
8 3 1 1 2
2 5 0 2 2
2 1 1 1 1
1 5 0 1 3
1 4 0 1 1
9 7 1 1 3
3 1 0 2 5
6 3 1 2 1
5 3

輸出樣例1:

Time = 6: 5 => 4 => 8 => 3
Distance = 3: 5 => 1 => 3

輸入樣例2:

7 9
0 4 1 1 1
1 6 1 3 1
2 6 1 1 1
2 5 1 2 2
3 0 0 1 1
3 1 1 3 1
3 2 1 2 1
4 5 0 2 2
6 5 1 2 1
3 5

輸出樣例2:

Time = 3; Distance = 4: 3 => 2 => 5

7-14 喊山 (30分)

喊山,是人雙手圍在嘴邊成喇叭狀,對著遠方高山發出“喂—喂喂—喂喂喂……”的呼喚。呼喚聲通過空氣的傳遞,迴盪於深谷之間,傳送到人們耳中,發出約定俗成的“訊號”,達到聲訊傳遞交流的目的。原來它是彝族先民用來求援呼救的“訊號”,慢慢地人們在生活實踐中發現了它的實用價值,便把它作為一種交流工具世代傳襲使用。(圖文摘自:http://news.xrxxw.com/newsshow-8018.html)

一個山頭呼喊的聲音可以被臨近的山頭同時聽到。題目假設每個山頭最多有兩個能聽到它的臨近山頭。給定任意一個發出原始訊號的山頭,本題請你找出這個訊號最遠能傳達到的地方。

輸入格式:

輸入第一行給出3個正整數nmk,其中n(≤10000)是總的山頭數(於是假設每個山頭從1到n編號)。接下來的m行,每行給出2個不超過n的正整數,數字間用空格分開,分別代表可以聽到彼此的兩個山頭的編號。這裡保證每一對山頭只被輸入一次,不會有重複的關係輸入。最後一行給出k(≤10)個不超過n的正整數,數字間用空格分開,代表需要查詢的山頭的編號。

輸出格式:

依次對於輸入中的每個被查詢的山頭,在一行中輸出其發出的呼喊能夠連鎖傳達到的最遠的那個山頭。注意:被輸出的首先必須是被查詢的個山頭能連鎖傳到的。若這樣的山頭不只一個,則輸出編號最小的那個。若此山頭的呼喊無法傳到任何其他山頭,則輸出0。

輸入樣例:

7 5 4
1 2
2 3
3 1
4 5
5 6
1 4 5 7

輸出樣例:

2
6
4
0
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
struct node{
    int x,num;
}s,s2;
vector<int> v[10005];
int vis[10005],maxx,ans;
void BFS(int t)
{
    memset(vis,0,sizeof(vis));
    queue<node> q;
    s.x=t,s.num=1;
    q.push(s);
    maxx=-1;vis[t]=1;ans=t;
    while(!q.empty())
    {
        node s1=q.front();q.pop();
        if(s1.num>maxx) maxx=s1.num,ans=s1.x;
        else if(s1.num==maxx) ans=min(s1.x,ans);
        for(int i=0;i<v[s1.x].size();i++)
        {
            if(!vis[v[s1.x][i]])
            {
                s2.x=v[s1.x][i],s2.num=s1.num+1;
                q.push(s2);
                vis[s2.x]=1;
            }
        }
    }
}
int main()
{
    int n,m,k,a,b,t;
    cin>>n>>m>>k;
    for(int i=0;i<m;i++)
    {
        cin>>a>>b; 
        v[a].push_back(b);
        v[b].push_back(a);
    }
    for(int i=0;i<k;i++)
    {
        cin>>t;
        BFS(t);
        if(ans==t)cout<<"0"<<endl;
        else cout<<ans<<endl;       
	}
	return 0;
}


7-15 長城 (30分)

正如我們所知,中國古代長城的建造是為了抵禦外敵入侵。在長城上,建造了許多烽火臺。每個烽火臺都監視著一個特定的地區範圍。一旦某個地區有外敵入侵,值守在對應烽火臺上的士兵就會將敵情通報給周圍的烽火臺,並迅速接力地傳遞到總部。

現在如圖1所示,若水平為南北方向、垂直為海拔高度方向,假設長城就是依次相聯的一系列線段,而且在此範圍內的任一垂直線與這些線段有且僅有唯一的交點。

圖 1

進一步地,假設烽火臺只能建造線上段的端點處。我們認為烽火臺本身是沒有高度的,每個烽火臺只負責向北方(圖1中向左)瞭望,而且一旦有外敵入侵,只要敵人與烽火臺之間未被山體遮擋,哨兵就會立即察覺。當然,按照這一軍規,對於南側的敵情各烽火臺並不負責任。一旦哨兵發現敵情,他就會立即以狼煙或烽火的形式,向其南方的烽火臺傳遞警報,直到位於最南側的總部。

以圖2中的長城為例,負責守衛的四個烽火臺用藍白圓點示意,最南側的總部用紅色圓點示意。如果紅色星形標示的地方出現敵情,將被哨兵們發現並沿紅色折線將警報傳遞到總部。當然,就這個例子而言只需兩個烽火臺的協作,但其他位置的敵情可能需要更多。

然而反過來,即便這裡的4個烽火臺全部參與,依然有不能覆蓋的(黃色)區域。

圖 2

另外,為避免歧義,我們在這裡約定,與某個烽火臺的視線剛好相切的區域都認為可以被該烽火臺所監視。以圖3中的長城為例,若A、B、C、D點均共線,且在D點設定一處烽火臺,則A、B、C以及線段BC上的任何一點都在該烽火臺的監視範圍之內。

圖 3

好了,倘若你是秦始皇的太尉,為不致出現更多孟姜女式的悲劇,如何在保證長城安全的前提下,使消耗的民力(建造的烽火臺)最少呢?

輸入格式:

輸入在第一行給出一個正整數N(3 ≤ N ≤105),即刻畫長城邊緣的折線頂點(含起點和終點)數。隨後N行,每行給出一個頂點的xy座標,其間以空格分隔。注意頂點從南到北依次給出,第一個頂點為總部所在位置。座標為區間[−109,109)內的整數,且沒有重合點。

輸出格式:

在一行中輸出所需建造烽火臺(不含總部)的最少數目。

輸入樣例:

10
67 32
48 -49
32 53
22 -44
19 22
11 40
10 -65
-1 -23
-3 31
-7 59

輸出樣例:

2