ICPC训练联盟2021寒假冬令营(2)

ICPC训练联盟2021寒假冬令营(2)

A - Maya Calendar

题目

上周末,M. A. Ya教授对古老的玛雅有了一个重大发现。从一个古

老的节绳(玛雅人用于记事的工具)中,教授发现玛雅人使用

Haab历法,一年有365天。Haab历法每年有19个月,在前18个月,

每月有20天,月份的名字分别是pop, no, zip, zotz, tzec, xul, yoxkin,

mol, chen, yax, zac, ceh, mac, kankin, muan, pax, koyab, cumhu。这

些月份中的日期用0到19表示;Haab历的最后一个月叫做uayet,

它只有5天,用0到4表示。玛雅人认为这个日期最少的月份是不

吉利的:在这个月,法庭不开庭,人们不从事交易,甚至不打扫

房屋。

因为宗教的原因,玛雅人还使用了另一个历法,这个历法中年被

称为Tzolkin历法(holly年),一年被分成13个不同的时期,每个

时期有20天,每一天用一个数字和一个单词相组合的形式来表示。

使用的数字是1~13,使用的单词共有20个,它们分别是:imix, ik,

akbal, kan, chicchan, cimi, manik, lamat, muluk, ok, chuen, eb, ben, ix,

mem, cib, caban, eznab, canac, ahau。注意:年中的每一天都有着

明确唯一的描述,比如,在一年的开始,日期如下描述: 1 imix,

2 ik, 3 akbal, 4 kan, 5 chicchan, 6 cimi, 7 manik, 8 lamat, 9 muluk, 10

ok, 11 chuen, 12 eb, 13 ben, 1 ix, 2 mem, 3 cib, 4 caban, 5 eznab, 6

canac, 7 ahau, 8 imix, 9 ik, 10 akbal ……也就是说数字和单词各自独

立循环使用。

Haab历和Tzolkin历中的年都用数字0,1,……表示,数字0表示世

界的开始。所以第一天被表示成:

• Haab: 0. pop 0

• Tzolkin: 1 imix 0

• 请您帮助M. A. Ya教授,编写一个程序,把Haab历转化成Tzolkin历。

输入

• Haab历中的数据由如下的方式表示:

NumberOfTheDay. Month Year(日期. 月份 年数)

• 输入中的第一行表示要转化的Haab历日期的数据量。接下来的每一行

表示一个日期,年数小于5000。

输出

• Tzolkin历中的数据由如下的方式表示:

Number NameOfTheDay Year(天数字 天名称 年数)

• 第一行表示输出的日期数量。下面的每一行表示一个输入数据中对应

的Tzolkin历中的日期。

Sample Input

3
10. zac 0
0. pop 0
10. zac 1995

Sample Output

3
3 chuen 0
1 imix 0
9 cimi 2801

分析

日历转换,将Haab历转化成Tzolkin历,输入Haab历(日期.月份 年数),输出Tzolkin历(天数字 天名称 年数)

算出总的天数来,用天数去换算。

代码

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
typedef long long ll;
int main()
{
    int t;
    cin>>t;
    cout<<t<<endl;
    string haab[20]={"pop","no","zip","zotz","tzec",
                     "xul","yoxkin","mol","chen","yax",
					 "zac","ceh","mac","kankin","muan",
					 "pax","koyab","cumhu","uayet"};
    string tzolkin[20]={"imix","ik","akbal","kan","chicchan",
                        "cimi","manik","lamat","muluk","ok",
                       "chuen","eb","ben","ix","mem",
					   "cib","caban","eznab","canac","ahau"};
    while(t--)
    {
        int d,y,i;
        char c;
        string m;
        cin>>d>>c>>m>>y;
        int ans;
        for(i=0;i<19;i++)
        {
            if(m==haab[i])
            {
                ans=y*365+i*20+d+1;//总的天数
                break;
            }
        }
        //1~13,,0~19,不一样
        cout<<(ans-1)%13+1<<" "<<tzolkin[(ans-1)%20]<<" "<<(ans-1)/260<<endl;
    }
    return 0;
}

B - Diplomatic License

题目

为了尽量减少外交开支,世界各国讨论如下。每一个国家最多只与一个国家

保持外交关系是不够的,因为世界上有两个以上的国家,有些国家不能通过

(一连串的)外交官进行相互交流。

• 本题设定每个国家最多与另外两个国家保持外交关系。平等对待每个国家是

一条不成文的外交惯例。因此,每个国家都与另外两个国家保持外交关系。

• 国际地形学家提出一种适合这一需求的结构。他们将安排国家组成一个圈,

使得每个国家都与其左右两个邻国建立外交关系。在现实世界中,一个国家

的外交部是设在这个国家的首都。为了简单起见,本题设定,首都的位置是

二维平面上的一个点。如果您用直线把保持外交关系的相关国家的外交部联

起来,结果就是一个多边形。

• 现在,要为两个国家之间的双边外交会议设定地点。同样,出于外交原因,

两国的外交官前往该地点的距离必须相等。为了提高效率,应尽量缩短行驶

距离,请您为双边外交会议做好准备。

输入

• 输入给出若干测试用例。每个测试用例首先给出数字n,表示涉及n

国家。本题设定n3是一个奇数。然后,给出n对x和y坐标,表示外交

部的位置。外交部的坐标是绝对值小于1012的整数。国家的排列顺序

与它们在输入中出现的顺序相同。此外,在列表中,第一个国家是最

后一个国家的邻国。

输出

• 对于每个测试用例,首先输出测试用例中国家的数量(=n),然后给

出国家之间的双边外交会议地点位置的x和y坐标。输出的会议地点的

顺序应与输入给出的顺序相同。从排在最前的两个国家的会议地点开

始,一直到排在最后面的两个国家的会议地点,最后输出第n个国家和

第一个国家的会议地点。

• **提示:**国家之间组成一个圈可以被视为一个多边形。

Sample Input

5 10 2 18 2 22 6 14 18 10 18
3 -4 6 -2 4 -2 6
3 -8 12 4 8 6 12

Sample Output

5 14.000000 2.000000 20.000000 4.000000 18.000000 12.000000 12.000000 18.000000 10.000000 10.000000
3 -3.000000 5.000000 -2.000000 5.000000 -3.000000 6.000000
3 -2.000000 10.000000 5.000000 10.000000 -1.000000 12.000000

分析

本题给出n个点的坐标,这n个点围城一个多边形,求这个多边形的n条边的中点坐标。最后一个中点坐标是输入的起点和终点的中点坐标。

用结构表示点的x和y坐标,由中点坐标公式给出两个相邻点的中点坐标。

就是求两个点的中点坐标,用中点坐标公式,注意最后一个中点坐标不一样。

代码

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
typedef struct
{
    ll x;
    ll y;
    double midx;
    double midy;//用float就wa了,,,以后都得用doule
}location;
location loc[10000];
int main()
{
    int n;
    while(cin>>n)
    {
        cin>>loc[0].x>>loc[0].y;
        for(int i=1;i<n;i++)
        {
            cin>>loc[i].x>>loc[i].y;
            loc[i].midx=(loc[i].x+loc[i-1].x)/2.0;
            loc[i].midy=(loc[i].y+loc[i-1].y)/2.0;
        }
        loc[n].midx=(loc[n-1].x+loc[0].x)/2.0;
        loc[n].midy=(loc[n-1].y+loc[0].y)/2.0;
        cout<<n<<" ";
        for(int i=1;i<n;i++)
        {
            printf("%.6f %.6f ",loc[i].midx,loc[i].midy);
        }
        printf("%.6f %.6f\n",loc[n].midx,loc[n].midy);
    }

    return 0;
}

C - “Accordian” Patience

题目

• 请您模拟"Accordian" Patience游戏,规则如下:

• 玩家将一副扑克牌一张一张地发牌,从左到右排成一排,不能重叠。

只要一张扑克牌和左边的第一张牌或左边的第三张牌相匹配,就将这

张扑克牌移被匹配的牌的上面。所谓两张牌匹配是这两张牌的数值

(数字或字母)相同或花色相同。每当移了一张牌之后,就再检查看

这张牌能否继续往左移,每次只能移在牌堆顶部的牌。本游戏可以将

两个牌堆变成一个牌堆,如果根据规则,可以将右侧牌堆的牌一张一

张地移到左侧牌堆,就可以变成一个牌堆。本游戏尽可能地把牌往左

边移动。如果最后只有一个牌堆,玩家就赢了。

• 在游戏过程中,玩家可能会遇上一次可以有多种选择的情况。当两张

牌都可以被移动时,就移动最左边的牌。如果一张牌可以向左移动一

个位置或向左移动三个位置,则将其移动三个位置。

输入

• 输入给出发牌的顺序。每个测试用例由一对行组成,每行给出26

张牌,由单个空格字符分隔。输入文件的最后一行给出一个#作

为其第一个字符。每张扑克牌用两个字符表示。第一个字符是面

值(A=Ace,2-9,T=10,J=Jack,Q=Queen,K=King),第二个字

符是花色(C= Clubs(梅花),D=Diamonds(方块),H=Hearts

(红心),S=Spades(黑桃))。

输出

• 对于输入中的每一对行(一副扑克牌的52张牌),输出一行,给

出在对应的输入行进行游戏后,每一堆扑克牌中剩余的扑克牌的

数量。

Sample Input

QD AD 8H 5S 3H 5H TC 4D JH KS 6H 8S JS AC AS 8D 2H QS TS 3S AH 4H TH TD 3C 6S
8C 7D 4C 4S 7S 9H 7C 5D 2S KD 2D QH JD 6D 9D JC 2C KH 3D QC 6C 9S KC 7H 9C 5C
AC 2C 3C 4C 5C 6C 7C 8C 9C TC JC QC KC AD 2D 3D 4D 5D 6D 7D 8D TD 9D JD QD KD
AH 2H 3H 4H 5H 6H 7H 8H 9H KH 6S QH TH AS 2S 3S 4S 5S JH 7S 8S 9S TS JS QS KS
#

Sample Output

6 piles remaining: 40 8 1 1 1 1
1 piles remaining: 52

分析

本题给一副扑克牌,一共52张。首先,将扑克牌从左往右一张张

地排列。然后从左往右遍历,如果该牌和左边第一张牌或左边第

三张牌相匹配,那么就将这张牌移到被匹配的牌上,形成牌堆;

每次只能移动每堆牌最上面一张牌。两张牌匹配条件是面值相同

或者花色相同。每次移动一张牌后,还应检查牌堆,看有没有其

他牌能往左移动;如果没有,遍历下一张牌,直到不能移动牌为

止。最后,输出每一堆扑克牌中剩余的扑克牌的数量。

在参考程序中,扑克牌用带指针变量的结构体表示,其中两个字

符变量ab分别表示扑克牌的面值和花色,指针变量prepost

别指向从左往右的顺序中的前一张牌和后一张牌,而指针变量

down则指向所在牌堆的下一张牌。这副扑克牌表示为一个三相链

表,每一个牌堆用线性链表表示,而在牌堆顶部的牌,其pre

post分别指向前一个牌堆顶部的牌和后一个牌堆顶部的牌。

• 本题根据题目给定的规则,模拟发牌和移动牌的过程。这里要注

意, 根据题意,应先比较左边第三张,然后,再比较左边第一张。

代码

#include<iostream>
#include<cstdio>
using namespace std;
struct Node
{
    int size;//这一堆牌的张数
    Node *pre,*post;//这张牌的前后指针
    Node *down;//牌堆下一张牌的指针
    char a,b;
    Node(): pre(NULL),post(NULL),down(NULL),size(1) {}  //初始化指针和size
};
inline void insertNode(Node *&m,Node *&n)//节点n替代节点m
{
    n->post=m->post;//先把n插进来
    n->pre=m->pre;
    if(m->post)//再把n连上
        m->post->pre=n;
    if(m->pre)
        m->pre->post=n;
}
inline void takeoutNode(Node *&n)//节点n从堆顶取走
{
    if(n->down)//如果牌堆中有下一张牌
    {
        Node *down=n->down;
        insertNode(n,down);
        return;
    }
    if(n->pre)//如果有前驱和后继
        n->pre->post=n->post;
    if(n->post)
        n->post->pre=n->pre;
}
inline void inStackNode(Node *&m,Node *&n)//节点n放在节点m为堆顶的牌堆
{
    n->size=m->size+1;
    insertNode(m,n);
    n->down=m;
}
inline bool checkMovable(Node *n,Node *m)//检查节点n和节点m是否匹配
{
    return n->a==m->a||n->b==m->b;
}
inline void pre3(Node *&n)//左边第三张
{
    if(n->pre)//一点一点挪到左边第三张
        n=n->pre;
    if(n->pre)
        n=n->pre;
    if(n->pre)
        n=n->pre;
}
inline void pre1(Node *&n)//左边第一张
{
    if(n->pre)
        n=n->pre;
}
inline void deleteNodes(Node *&n)//删除操作,用于每个测试用例后,释放空间
{
    while(n)
    {
        Node *p=n->post;
        while(n)
        {
            Node *d=n->down;
            delete n;
            n=NULL;
            n=d;
        }
        n=p;
    }
}
int main()
{
    Node *head=new Node;//头节点
    while(true)
    {
        Node *it=new Node;//新节点
        it->a=getchar();
        if(it->a=='#')
            break;
        it->b=getchar();
        getchar();
        head->post=it;//链表初始化
        it->pre=head;
        for(int i=1;i<52;i++)//当前测试用例,52张牌构成线性链表
        {
            Node *p=new Node;//又一个新节点
            p->a=getchar();
            p->b=getchar();
            getchar();
            it->post=p;//连起来
            p->pre=it;
            it=p;
        }
        bool checkMove=true;
        while(checkMove)//移动牌规则
        {
            checkMove=false;
            it=head->post;//从头开始
            while(it)
            {
                Node *post=it->post;
                Node *p=it;
                pre3(p);//左边第三张是否匹配
                if(p&&p!=head&&checkMovable(p,it))
                {
                    checkMove =true;
                    takeoutNode(it);
                    inStackNode(p,it);
                    break;
                }
                p=it;
                pre1(p);//左边第一张是否匹配
                if(p&&p!=head&&checkMovable(p,it))
                {
                    checkMove=true;
                    takeoutNode(it);
                    inStackNode(p,it);
                    break;
                }
                it=post;
            }
        }
        
        it=head->post;
        int piles=0;
        while(it)
        {
            piles++;
            it=it->post;
        }
        if(piles==1)
            printf("%d piles remaining:",piles);//原来的标程是pile,wa了
        else
            printf("%d piles remaining:",piles);
        it=head->post;
        while(it)
        {
            printf(" %d",it->size);
            it=it->post;
        }
        putchar('\n');
        deleteNodes(head->post);//删除链表,释放空间
    }
    delete head;
    return 0;
}

D - Broken Keyboard (a.k.a. Beiju Text)

题目

您正在用一个坏键盘键入一个长文本。这个键盘的

问题是时不时“Home”键或“End”键会在您输入

文本时自动按下。您并没有意识到这个问题,因为

你只关注文本,甚至没有打开显示器。完成键入后,

您打开显示器,在屏幕上看到文本。在中文里,我

们称之为悲剧。请您是找到悲剧的文本。

输入

• 输入给出若干测试用例。每个测试用例都是一行,包含至少一个,

最多100,000个字母、下划线和两个特殊字符‘[’和‘]’;其中‘[’表示

“Home”键,而‘]’表示“End”键。输入以EOF结束。

输出

• 对于每个测试用例,输出在屏幕上的悲剧的文本。

Sample Input

This_is_a_[Beiju]_text
[[]][][]Happy_Birthday_to_Tsinghua_University

Sample Output

BeijuThis_is_a__text
Happy_Birthday_to_Tsinghua_University

分析

本题题意:

•对于每个输入的字符串,如果出现’ [ ',则

输入光标就跳到字符串的最前面,如果出

现’ ] ',则输入光标就跳到字符串的最后面。

输出实际上显示在屏幕上的字符串。• 将输入的字符串表示为链表,再输出。其中,每个字符为链表中

的元素的数据,而指针指向按序输出的下一个元素。

• 用数组模拟链表链表:用数组next代替链表中的next指针,例如,

第一个字符s[1]的下一个字符是s[2],则next[1]=2。此外,对于链

表,第0个元素不储存数据,作为辅助头结点,第一个元素开始

储存数据。

• 设置变量cur表示光标,cur不是当前遍历到的位置i,是表示位置i

的字符应该插入在cur的右侧。如果当前字符为’ [ ',光标cur就跳

到字符串的最前面,即cur=0;如果’ ] ',光标就跳到字符串的最

后面,即cur=last,其中变量last保存当前字符串最右端的下标。

• 程序根据试题描述给出的规则进行模拟。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
const int N=100010;
string s;
int nex[N];
int main()
{
    while(cin>>s)
    {
        s="#"+s;//将字符串整体后移一下,s[0]空出
        int cur=0;
        int last=0;
        nex[0]=0;//不指向任何值
        int len=s.size();
        for(int i=1;i<len;i++)
        {
            if(s[i]=='[')
                cur=0;//碰到[,光标移到开头
            else if(s[i]==']')//光标移到末尾
                cur=last;
            else//链表节点逐一串联
            {
                nex[i]=nex[cur];
                nex[cur]=i;//这两行是链表的插入操作
                if(last==cur)
                    last=i;//当末尾值和当前光标位置相同时,last和cur一样向i跟进
                cur=i;//改变光标位置
            }
        }
        for(int i=nex[0];i!=0;i=nex[i])//链表最后一个节点指向0
            cout<<s[i];
        cout<<endl;
    }
    return 0;
}

E - Satellites

题目

在这里插入图片描述

输入

• 输入包含一个或多个测试用例。

• 每个测试用例一行,给出两个整数sa,以及一个字符串”min”

或”deg”;其中s是人造卫星与地球表面的距离,a是这两颗人造卫

星对地球中心的夹角。以分(′),或者以度(◦),为单位。输入不会

既给出分,又给出度。

输出

• 对于每个测试用例,输出一行,给出两个卫星之间的圆弧距离和

直线弦距离,以公里为单位。距离是一个浮点数,保存小数点后

的六位数字

Sample Input

500 30 deg
700 60 min
200 45 deg

Sample Output

3633.775503 3592.408346
124.616509 124.614927
5215.043805 5082.035982

分析

在这里插入图片描述

代码

#include<iostream>
#include<string>
#include<cmath>
using namespace std;
const double pi=3.1415926535898;
int main()
{
    double s,a;
    string str;
    while(cin>>s>>a>>str)
    {
        double ad,cd;
        s+=6440;
        if(str=="min")
        {
            a/=60;
        }
        if(a>180)
            a=360-a;
        ad=2*pi*s*(a/360);
        cd=s*sin(a*pi/360)*2;
        printf("%.6f %.6f\n",ad,cd);
    }
    return 0;
}

F - Fourth Point !!

题目

给出平行四边形中两条相邻边的端点

的(x, y)坐标,请找到第四个点的(x, y)

坐标。

输入

• 输入的每行给出8个浮点数:首先,给出第一条边的一个端点和

另一个端点的(x, y)坐标;然后,给出第二条边的一个端点和另一

个端点的(x, y)坐标;所有的坐标均以米为单位,精确到毫米。所

有的坐标的值在-10000和+10000之间。输入以EOF终止。

输出

• 对于每行输入,输出平行四边形的第四个点的(x, y)坐标,以米为

单位,精确到毫米,用一个空格隔开xy

Sample Input

0.000 0.000 0.000 1.000 0.000 1.000 1.000 1.000
1.000 0.000 3.500 3.500 3.500 3.500 0.000 1.000
1.866 0.000 3.127 3.543 3.127 3.543 1.412 3.145

Sample Output

1.000 0.000
-2.500 -2.500
0.151 -0.398

分析

给出平行四边形中两条相邻边的端点坐标,求第4个点的坐标。

要注意的是,两条相邻边的端点坐标,会有两个点的坐标是重复

的;因此,要判定哪两个点的坐标是重复的。

• 设给出的平行四边形中两条相邻边的端点坐标为(X0 , y0),(x1 , y1),

(x2 , y2)和(x3 , y3),(x0 , y0 )= (x3 , y3),求第4个点的坐标(xa , yb),则有

xa-x2= x1-x0ya-y2= y1-y0 ;得xa=x2+x1-x0ya= y2+y1-y0

• 在参考C++程序中,使用交换函数swap。交换函数swap包含在命

名空间std 里面,使用swap,不用担心交换变量精度的缺失,无

需构造临时变量,也不会增加空间复杂度

代码

#include<iostream>
#include<algorithm>
using namespace std;
struct point
{
    double x,y;
}p[5];
bool cmp(int a,int b)
{
    if(p[a].x==p[b].x&&p[a].y==p[b].y)
        return true;
    else return false;
}
int main()
{
    while(cin>>p[0].x>>p[0].y)
    {
        for(int i=1;i<=3;i++)
            cin>>p[i].x>>p[i].y;
        if(cmp(0,2))
            swap(p[2],p[3]);
        else if(cmp(1,3))
            swap(p[0],p[1]);
        else if(cmp(1,2))
        {
            swap(p[0],p[1]);
            swap(p[2],p[3]);
        }
        printf("%.3f %.3f\n",p[1].x+p[2].x-p[0].x,p[1].y+p[2].y-p[0].y);
    }
    return 0;
}

G - The Circumference of the Circle

题目

要计算圆的周长似乎是一件容易的事,只

要您知道圆的直径。但是,如果您不知道

呢?给出平面上的3个非共线点的笛卡尔

坐标。你的工作是计算与这3个点相交的

唯一的圆的周长。

输入

• 输入包含一个或多个测试用例,每个测试用例一行,包含6个实

x1 , y1, x2, y2 , x3 , y3 ,表示3个点的坐标。由这3个点确定的直径不

超过1百万。输入以文件结束终止。

输出

• 对每个测试用例,输出一行,给出一个实数,表示3个点所确定

圆的周长。输出的周长精确到小数两位。Pi的值为

3.141592653589793。

Sample Input

0.0 -0.5 0.5 0.0 0.0 0.5
0.0 0.0 0.0 1.0 1.0 1.0
5.0 5.0 5.0 7.0 4.0 6.0
0.0 0.0 -1.0 7.0 7.0 7.0
50.0 50.0 50.0 70.0 40.0 60.0
0.0 0.0 10.0 0.0 20.0 1.0
0.0 -500000.0 500000.0 0.0 0.0 500000.0

Sample Output

3.14
4.44
6.28
31.42
62.83
632.24
3141592.65

分析

此题的关键是求出与这3个点相交的唯一

圆的圆心。设3个点分别为(x0, y0),(x1 , y1)

和(x2 , y2),圆心为 (x**m, y**m)。

•本题采用初等几何知识解题。

在这里插入图片描述

代码

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
#define  PI 3.141592653589793
int main()
{
    double x1,y1,x2,y2,x3,y3;
    while(cin>>x1>>y1>>x2>>y2>>x3>>y3)
    {
        double a,b,c,p,s,d;
        a=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
        b=sqrt((x1-x3)*(x1-x3)+(y1-y3)*(y1-y3));
        c=sqrt((x2-x3)*(x2-x3)+(y2-y3)*(y2-y3));
        p=(a+b+c)/2;
        s=sqrt(p*(p-a)*(p-b)*(p-c));
        d=a*b*c/(2*s);
        printf("%.2f\n",d*PI);
    }
    return 0;
}

H - Titanic

题目

这是一个历史事件,在“泰坦尼克号”的传奇航程中,无线电已经

接到了6封电报警告,报告了冰山的危险。每封电报都描述了冰

山所在的位置。第5封警告电报被转给了船长。但那天晚上,第6

封电报被延误,因为电报员没有注意到冰山的坐标已经非常接近

当前船的位置了。

• 请您编写一个程序,警告电报员冰山的危险!

输入

• 输入电报信息的格式如下:

• Message #.

• Received at ::.

• Current ship’s coordinates are

• ^’" <NL/SL>

• and ^’" <EL/WL>.

• An iceberg was noticed at

• ^’" <NL/SL>

• and ^’" <EL/WL>.

• ===

• 这里的是一个正整数,::是接收到电报的时间;

^’" <NL/SL>和^’" <EL/WL>表示"北(南)纬

x1度x2分x3秒 和东(西)经Y1度Y2分Y3秒。

输出

• 程序按如下格式输出消息:

• The distance to the iceberg: miles.

• 其中是船和冰山之间的距离(即在球面上船和冰山之间的最短

路径),精确到两位小数。如果距离小于(但不等于!)100英

里,程序还要输出一行文字:DANGER!

提示:

• 为了简化计算,假设地球是一个理想的球体,直径为6875英里,

完全覆盖水。本题设定输入的每行按样例输入所显示的换行。船

舶和冰山的活动范围在地理坐标上,即从0到90度的北纬/南纬

(NL/SL)和从0到180度的东经/西经(EL/WL)

Sample Input

Message #513.
Received at 22:30:11. 
Current ship's coordinates are 
41^46'00" NL 
and 50^14'00" WL.
An iceberg was noticed at
41^14'11" NL 
and 51^09'00" WL.
===

Sample Output

The distance to the iceberg: 52.04 miles.
DANGER!

分析

在这里插入图片描述

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
char tmp[100],dir_e[10],dir_n[10];
double x[4],y[4],a[4],b[4];
double ans = 0;
double ship_n,ship_e,ice_n,ice_e;
int flag_n = 1, flag_e = 1;

double dist(double l1, double d1, double l2, double d2)//计算两点距离;
{
    double r=6875.0/2;//地球半径
    double p=acos(-1.0);//π
    l1*=p/180,d1*=p/180;//度转换为弧度
    l2*=p/180,d2*=p/180;
    return r*acos(cos(l1)*cos(l2)*cos(d1-d2)+sin(l1)*sin(l2));//距离
}
int main()
{
    for(int i=1;i<=3;i++)
    {
        gets(tmp);
    }
    scanf("%lf^%lf'%lf\" %s\n",&x[1],&x[2],&x[3],dir_n);
    scanf("and %lf^%lf'%lf\" %s\n",&y[1],&y[2],&y[3],dir_e);
    if(strcmp(dir_n,"SL")==0)
        flag_n=-1;
    if(strcmp(dir_e,"WL.")==0)
        flag_e=-1;
    ship_n=flag_n*(x[1]+x[2]/60+x[3]/3600);
    ship_e=flag_e*(y[1]+y[2]/60+y[3]/3600);
    flag_n=1,flag_e=1;
    gets(tmp);
    scanf("%lf^%lf'%lf\"%s\n",&a[1],&a[2],&a[3],dir_n);
    scanf("and %lf^%lf'%lf\" %s\n",&b[1],&b[2],&b[3],dir_e);
    if(strcmp(dir_n,"SL")==0) flag_n=-1;
    if(strcmp(dir_e,"WL.")==0) flag_e=-1;
    ice_n=flag_n*(a[1]+a[2]/60+a[3]/3600);
    ice_e=flag_e*(b[1]+b[2]/60+b[3]/3600);
    gets(tmp);
    ans=dist(ship_n,ship_e,ice_n,ice_e);//船和冰川的距离
    printf("The distance to the iceberg: %.2lf miles.\n",ans);
    if(floor(ans+0.005)<100)//距离小于100英里
        puts("DANGER!");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HHHᕙ(`▿´)ᕗ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值