冬令营第二天(1.19)

问题A:Maya Calendar

题目链接:poj1008

题目大意:有两种计算日期的方式。给出Haab历输出Tzolkin历,只需模拟转换即可,具体细节看代码

Haab历:一年为365天,一年分为19个月,前18个月每个月都是20天,第19个月为5天,每一个月都有一个名字,分别为pop, no, zip, zotz, tzec,
xul, yoxkin, mol, chen, yax, zac, ceh, mac, kankin, muan, pax, koyab, cumhu和uayet,每个月份中的天数用0到19表示。最后一个月份中的天数用0到4表示。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
pop no zip zotz tzec xul yoxkin mol chen yax zac ceh mac kankin muan pax koyab cumhu uayet

一种叫Tzolkin:一年为260天,一年分为13段,每段20天(260=13*20),每一天用一个数字和一个名字表示,总共20个名字: imix, ik, akbal, kan, chicchan, cimi, manik, lamat, muluk, ok, chuen, eb, ben, ix, mem, cib, caban, eznab, canac, ahau,数字为1到13,数字和名字都顺序循环(类似中国的天干地支)。例如,第一年开始的几天为:1 imix, 2 ik, 3 akbal, 4 kan, 5 chicchan

参考代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include <vector>
#include<stack>
#include<map>
#include<string>
#include<cstring>
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);
#define inf 0x3f3f3f3f
#define SC(a) scanf("%d",&a)
#define pr(a) printf("%d",a)
#define mem(a) memset(a,0,sizeof(a))
#define fn for(int i = 1; i <= n; i++)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
string Haab[19] = {
    
    "pop", "no", "zip", "zotz",
                   "tzec", "xul", "yoxkin", "mol", "chen", "yax",
                   "zac", "ceh", "mac", "kankin", "muan", "pax",
                   "koyab", "cumhu", "uayet"};
/* 定义Tzolkin的20天*/
string Tzolkin[20] = {
    
    "imix", "ik", "akbal", "kan", "chicchan", "cimi",
                      "manik", "lamat", "muluk", "ok", "chuen", "eb", 
					  "ben", "ix", "mem","cib", "caban", 
					  "eznab", "canac", "ahau"};
// 日期表示的信息
struct Data
{
    
    
    int Date;
    //string类型的month
    string Month;
    int Year;
};
//日期转换函数

void convert(Data &x)
{
    
    
    //代表从世界开始记起的天数
    long current;
    //代表月份
    int month;
    //寻找haab月份代表是那个数字
    for (month = 0; month < 20; month++) //当前月份是Haab历的哪个月
    {
    
    
        if (x.Month == Haab[month])
            break;
    }
    current = x.Year * 365 + month * 20 + x.Date + 1;
    int num, year = 0; // num为输出中的数字,year为输出中的年份 
    string word;       // 月份名称 
    //求月份的时候会遇到两种情况
    /* 余数为0则为一个整月num=13
        余数不为零则月数等于余数
     */
    if (current % 13 == 0)
    {
    
    
        num = 13; 
    }
    else
    {
    
    
        num = current % 13;
    }
    //求年份
    // 减260天即可 
    while ((current - 260) > 0)
    {
    
    
        ++year;
        current -= 260;
    }
    //开始判断天数
    //如果天数=0说明是上一年的最后一天
    if (current == 0)
    {
    
    
        word = "ahau";
    }
    else
    {
    
    
        //除以20继续判断
        current = current % 20;
        //和之前判断天数一样
        if (current == 0)
        {
    
    
            word = "ahau"; // 表示前一个月的最后一天 
        }
        else
        {
    
    
            word = Tzolkin[current - 1];
        }
        cout<<num<<" "<<word<<" "<<year<<endl;
    }
}

int main()
{
    
    
    int i, n;
    char ch; //储存.字符
    //输入的第一行表示要转化的日期数量n
    cin>>n;
    //创建一个一维数组
    Data *p = new Data[n];
    for (int i = 0; i < n; i++)
    {
    
    
        cin>>p[i].Date>>ch>>p[i].Month>>p[i].Year;
    }
    printf("%d\n", n);
    for (int i = 0; i < n; i++)
    {
    
    
        convert(p[i]);
    }
    return 0;
}

问题B:Diplomatic License

题目:poj1939

思路:简而言之,读题难度>>(远大于)做题 ps:我用cin输入会Output Limit scnaf输入就AC了(离奇事件?~~~

题目意思:

给你n(n>=3且n为奇数)个点的坐标,这n(按构成多边形的顺序输入的)个点必然构成一个多边形,要你按输入顺序输出这个多边形各边的中点坐标。结果保留6位有效数字。

参考代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include <vector>
#include<stack>
#include<map>
#include<string>
#include<cstring>
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);
#define inf 0x3f3f3f3f
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
struct point{
    
    
	ll x,y;
}now,first,last;
int n;

int main()
{
    
    
	while(cin>>n,n)
	{
    
    
		cout<< n << endl;
		cin >> first.x >> first.y;
		now = first;
		for(int i = 1; i < n; ++i)
		{
    
    
			cin >> last.x >> last.y;
			printf("%.6f%.6f",(last.x+now.x)/2.0,(now.y + last.y )/2.0);
			now = last;
		}
		printf("%.6f%.6f",(last.x + first.x )/2.0 , (last.y + first.y)/2.0);
		cout << "\n";
	}
	return 0;
}

问题C:Accordian“ Patience

题目:poj1214
题目大意:

给出52张牌的花色和点数,从左往右每个成为一个堆。
当某个堆的堆顶与它左边第三个(优先考虑第三个)的花色或是点数相等,就将这堆放置在与之相等的堆上,倘若出现空隙,出现空隙,需要右边所有堆向左移动来填补。

思路:

  1. 利用动态数组vector来模拟链表
  2. 由题意可知是先入后出,可以采用stack栈来实现
  3. 易知牌由两个成员组成,可以用结构体或者pair实现

参考代码:

#include<iostream>
#include<cstring>
#include<string> 
#include<algorithm>
#include<stack>
#include<vector>
#include<map>
using namespace std;
vector<stack<pair<char,char> > > v;//动态数组vector中存放为栈,栈里可以用结构体或pair 

void creat(char a, char b) // 创建 
{
    
    
	stack<pair<char,char> > s;
	s.push(make_pair(a,b));
	v.push_back(s); 
}

bool move(int x) // 移动是否成功 
{
    
    
	char a=v[x].top().first, b=v[x].top().second; 
	// 优先考虑左边第三个 
	if(x>=3)
	{
    
    
		char aa=v[x-3].top().first, bb=v[x-3].top().second;
		if(aa==a || bb==b) // 花色或者点数相等 
		{
    
    
			v[x].pop();
			if(v[x].empty()) v.erase(v.begin() + x); // 如果该堆为空,需要这个右边全部往左移 
			v[x-3].push(make_pair(a,b));
			return true;
		}
	}
	if(x>=1) //其次考虑左边第一个 
	{
    
    
		char aa=v[x-1].top().first, bb=v[x-1].top().second;
		if(aa == a || bb == b){
    
    
			v[x].pop();
			if(v[x].empty()) v.erase(v.begin() + x);
			v[x-1].push(make_pair(a,b));
			return true;
			}
	}	
	return false;
}


int main()
{
    
    
	string s;
	while(1)
	{
    
    
		for(int i=1; i<=26; i++) //每行读取26个,注:若需读取带空格的字符串需用:getline(cin,s) 
		{
    
    
			cin >> s;
			if(s[0]=='#') break;
			creat(s[0],s[1]); 
		}
		if(s[0]=='#') break;//结束标志 
		for(int i = 1; i <= 26; i++)
		{
    
    
			cin >> s;
			creat(s[0], s[1]);
		}
		while(1)
		{
    
    
			int f=1;
			int n=v.size();
			for(int i = 0; i < n; i++){
    
    	
				if(move(i)){
    
    
					f = 0;
					break;
				}
			}
			if(f) break;
		}
		int res = v.size();
		if(res >= 1) cout << res << " piles remaining:"; // 这里注意,讲道理res=1应该输出pile,但oj输出了piles 
		else cout << res << " pile remaining:";
		for(int i = 0; i < res; i++) cout << " " << v[i].size();
		cout << endl;
		v.clear() ;
	}
	return 0;
}

问题D:Broken Keyboard (a.k.a. Beiju Text)

题目链接:UVA11988

题意:

输入字符串,如果出现‘[’,就输入光标跳到了字符串的最前面,如果出现‘]’,则输入光标跳到字符串最后面。最后输出实际显示在屏幕上的字符串

思路:

将输出的字符串用数组模拟链表,用一个next数组代替链表的next指针。设置cur来表示光标的位置,cur不是当前遍历到的位置i表示位置i的字符应该插入cur的右侧,,当出现‘[’ cur=0; 出现’]’ cur=last last用来保存字符串最右边的下标;

参考代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int main()
{
    
    
	char s[maxn];
	while(~scanf("%s",s+1))
	{
    
    
		int next[maxn]={
    
    0};//清空,初始化
		int cur=0,last=0;
		for(int i=1; s[i]; ++i)
		{
    
    
			if(s[i]=='[') cur=0;
			else if(s[i]==']') cur=last;
			else
			{
    
    
				next[i]=next[cur];//插入链表
				next[cur]=i;
				if(cur==last) last=i;//last的更新
				cur=i;
			}
		}
		for(int i=next[0];i!=0;i=next[i])//输出
		{
    
    
			if(s[i]!='['&&s[i]!=']') printf("%c",s[i]);
		}
		putchar('\n');
	}
	return 0;
} 

问题E:Satellites

题目链接:UVA10221

题目大意及思路:

给出半径跟夹角,求出弦长跟弧长;注意角度>180°,用360减去即可

在这里插入图片描述
如图:易知弧长:2πra/360 直线弦:rsin(aπ/2*180)*2
注意: 0<a<180
参考代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include <vector>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<cstring>
#define inf 0x3f3f3f3f
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const double r=6440;

int main()
{
    
    
	double ss,as;
	char s[10];
	while(cin >>ss >> as >> s)
	{
    
    
		if(s[0]=='m') as=as/60;//deg角度,min位分 
		double angle=M_PI*as/180;
		double arc=angle*(ss+r);
		double dis=2*(ss+r)*sin(angle/2);
		if(as>180) arc=2*M_PI*(ss+r)-arc; // 如果大于180°,就用总的减去 
		printf("%.6f %.6f\n",arc,dis);
	}
	return 0;
}

问题F:Fourth Point !!

题目链接:UVA10242
题目大意及思路:

给出一个四边形两条边的的四个点,求出第四个点,设为a,b,c,d,找出相同的点假设为bc,则第四个点 e就为a+d-c
注意输出保留三位小数

完整代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
using namespace std;
struct point{
    
    
	double x,y;
};

int main()
{
    
    
	point a,b,c,d,e;
	while(~scanf("%lf%lf%lf%lf",&a.x ,&a.y,&b.x ,&b.y))
	{
    
    
		scanf("%lf%lf%lf%lf",&c.x ,&c.y,&d.x ,&d.y);
		if(a.x==c.x && a.y==c.y)
		{
    
    
			e.x=b.x+d.x-a.x;
			e.y=b.y+d.y-a.y;
		}
		else if(a.x==d.x && a.y==d.y)
		{
    
    
			e.x=b.x+c.x-a.x;
			e.y=b.y+c.y-a.y;
		}
		else if(b.x==c.x && b.y==c.y)
		{
    
    
			e.x=a.x+d.x-b.x;
			e.y=a.y+d.y-b.y;
		}
		else if(b.x==d.x && b.y==d.y)
		{
    
    
			e.x=a.x+c.x-b.x;
			e.y=a.y+c.y-b.y;
		}
		printf("%.3f %.3f\n",e.x,e.y );
	}
	return 0;
}

问题G: The Circumference of the Circle

题目链接:poj2242

思路:

根据坐标,算出三边长。让根据海伦公式计算面积,再根据s=abc/4r 计算出外接圆半径,然后算出周长

海伦公式
外接圆半径
参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#define maxn 1000000
#define pi 3.141592653589793
using namespace std;
int main(){
    
    
    double x1,x2,x3,y1,y2,y3,l;
    while(cin>>x1>>y1>>x2>>y2>>x3>>y3){
    
    
        double a,b,c;
        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));
        l=a+b+c;
        l/=2;
        l=sqrt(l*(l-a)*(l-b)*(l-c));
        l=a*b*c/2/l;
        l*=pi;
        printf("%.2f\n",l);
    }
    return 0;
}

问题H:Titanic

题目链接:poj2354

题目大意:

给你一些字符串,其中包括了两个这个个球的经纬度,求距离,虽然是个理科生,对经纬度都不了解,但必应一下还是能找到公式:

公式:dis(A,B) = R*arccos(cos(wA)*cos(wB)*cos(jB-JA)+sin(wA)*sin(wB));

(wA表示A点的纬度,jA表示A点的精度,B类似),注意默认正方向为’N’,’E’;

关于公示的推导过程
输入就比较烦;
参考代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
char s[100010];
char c;
int f;
double r=6875/2.0;
int main()
{
    
    
    scanf("%*s%*s");
	scanf("%*s%*s%*s");
	scanf("%*s%*s%*s%*s");
    int a,b,c;
    scanf("%d^%d\'%d\"",&a,&b,&c);
    cin>>s;
    if(s[0]=='N') f=1;
    else f=-1;
    double wa=(a+b/60.0+c/3600.0)*f/180*acos(-1.0);
   scanf("%*s%d^%d\'%d\"",&a,&b,&c);
    cin>>s;
    if(s[0]=='E') f=1;
    else f=-1;
    double ja=(a+b/60.0+c/3600.0)*f/180*acos(-1.0);
   scanf("%*s%*s%*s%*s%*s");
    scanf("%d^%d\'%d\"",&a,&b,&c);
    cin>>s;
    if(s[0]=='N') f=1;
    else f=-1;
    double wb=(a+b/60.0+c/3600.0)*f/180*acos(-1.0);
    scanf("%*s%d^%d\'%d\"",&a,&b,&c);
    cin>>s;
    if(s[0]=='E') f=1;
    else f=-1;
    double jb=(a+b/60.0+c/3600.0)*f/180*acos(-1.0);
    cin>>s;
    double dis=r*acos(cos(wa)*cos(wb)*cos(jb-ja)+sin(wb)*sin(wa));
    printf("The distance to the iceberg: %.2f miles.\n",dis);
    if(dis+0.005<100) printf("DANGER!\n");
    return 0;
}

写了这么久,总结一下:

  1. 对于A,B题来说,读题,理解,码代码应该还可以再快一点。
  2. 最大的收获就是CD题的链表题,学会了动态数组模拟链表
  3. 后面的计算几何了解了球上两点最短距离

长路漫漫,唯有坚持!!!

猜你喜欢

转载自blog.csdn.net/ecjtu2020/article/details/113097612