電子科技大學第八屆ACM趣味程式設計競賽第二場題解
題解:
ans = sigma(1 - (1 - Pi/100)^ 2);
標程:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int N,p;
double ans=0.0;
scanf("%d",&N);
ans=N;
while(N--)
{
scanf("%d",&p);
p=100-p;
ans=ans-p*p*1.0/10000.0;
}
printf("%.3lf",ans);
return 0;
}
B可憐的非洲銀
題解:模擬每個碎片按照順序得到即可,注意每天先購買1個F碎片,輸出有先後順序
#include <stdio.h>
#include <stdlib.h>
int main()
{
int cnt[26];
char s[150];
int N,K,i,j,day=0,flag=0;
for(i=0;i<26;i++)cnt[i]=0;
scanf("%d%d",&N,&K);
for(i=0;i<N;i++)
{
scanf("%s",&s);
cnt['F'-'A']++;
for(j=0;s[j]!='\0';j++)
{
if(flag==1)
break;
cnt[s[j]-'A']++;
if(cnt['F'-'A']>=50){
printf("%d F",i+1);
flag=1;break;
}
if(cnt[s[j]-'A']>=50){
printf("%d %c",i+1,s[j]);
flag=1;break;
}
}
}
if(flag==0&&K>N)printf("AMNZ");
else if(flag==0)printf("Feizhou Yin");
return 0;
}
C簡單的數學題
題解:
a * 10 + b - (b * 10 + a )是9的倍數 說明交換相鄰數位之後 原數和新數的差是9的倍數,那你可以通過不斷交換獲得最小的數,即將各個位數從小到大排列後輸出即可
#include <stdio.h>
#include <stdlib.h>
int main()
{
int cnt[10]={0};
char ans[1010];
char s[1010];
scanf("%s",&s);
int i,p=0;
for(i=0;s[i]!='\0';i++)
cnt[s[i]-'0']++;
for(i=0;i<10;i++)
{
while(cnt[i])
{
cnt[i]--;
ans[p++]=i+'0';
}
}
ans[p++]='\0';
printf("%s",ans);
return 0;
}
D 我想上廁所
題解:
三種情況0個人上錯廁所 輸出02個人上錯廁所 選擇兩個方向最短的3個人上錯廁所 推導公式:兩個人之間有個間隔,總共有3個間隔,選取其中最短的2個
標程
#include<stdio.h>
int min(int a,int b)
{
return a<b?a:b;
}
int main()
{
int n,i,cnt,ans;
int a,p[5];
scanf("%d",&n);cnt=0;
for(i=1;i<=n;i++)
{
scanf("%d",&a);
if (a!=i)
{
cnt++;
p[cnt]=i;
}
}
if (cnt==0) ans=0;
if (cnt==2)
{
ans=min(p[2]-p[1],n-p[2]+p[1]);
ans=2*ans-1;
}
if (cnt==3)
{
ans=min(p[3]-p[1],n-(p[2]-p[1]));
ans=min(ans,n-(p[3]-p[2]));
ans=2*ans-2;
}
printf("%d\n",ans);
return 0;
}
E-Megumin的爆裂魔法
該題為計算幾何經典問題——最小圓覆蓋的簡化版,即n<=3的情況。
顯然,n==1時,最小圓退化為一個點。
n==2時,最小圓半徑為連線兩點的線段長度的一半,圓心位於線段中點。
n==3時,若三點構成一個鈍角三角形,則最小圓半徑為三角形最長邊長度的一半,圓心位於最長邊中點。
若構成的三角形是銳角或直角三角形,則最小圓為其外接圓。
考慮如何求外接圓圓心: <法一>
任取三角形的兩條邊,作它們的垂直平分線,求交點即可。
但是在程式中如何實現?如果僅僅依靠高中的斜截式直線方程,我們需要討論我們取的這兩條邊所在直線的斜率是否存在,是否為零,是否存在且非零這幾種情況,在第一份標程中,命題人所給出的就是這樣的做法。
該題的情況比較多,需要討論全面,同時對實數的處理也是一項挑戰。
在演算法競賽中,我們處理直線,一般用其上的一個點和一個方向向量,即引數式表示,這樣可以避免分類討論,比較容易求得垂直平分線和交點,請讀者自行思考。 #include<stdio.h>
#include<math.h>
#define EPS 0.00000001
int n;
typedef struct {double x,y;}Point;
typedef Point Vector;
double sqr(double x){return x*x;}
double dis(Point a,Point b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
Vector Minus (Point a,Point b){return (Vector){a.x-b.x,a.y-b.y};}
double dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;};
int check(Point a,Point b){
if(fabs(a.x-b.x)<EPS) return -1;
if(fabs(a.y-b.y)<EPS) return 1;
return 0;
}
Point a[3];
int main()
{
// freopen("09.in","r",stdin);
// freopen("09.out","w",stdout);
int i;
scanf("%d",&n);
for(i=0;i<n;++i) scanf("%lf%lf",&a[i].x,&a[i].y);
if(n==1) {printf("%.4f %.4f %.4f\n",0.0,a[0].x,a[0].y); return 0;}
if(n==2) {printf("%.4f %.4f %.4f\n",dis(a[0],a[1])*0.5,(a[0].x+a[1].x)*0.5,(a[0].y+a[1].y)*0.5); return 0;}
if(dot(Minus(a[1],a[0]),Minus(a[2],a[0]))<EPS) {printf("%.4f %.4f %.4f\n",dis(a[1],a[2])*0.5,(a[1].x+a[2].x)*0.5,(a[1].y+a[2].y)*0.5); return 0;}
else if(dot(Minus(a[1],a[2]),Minus(a[0],a[2]))<EPS) {printf("%.4f %.4f %.4f\n",dis(a[1],a[0])*0.5,(a[1].x+a[0].x)*0.5,(a[1].y+a[0].y)*0.5); return 0;}
else if(dot(Minus(a[0],a[1]),Minus(a[2],a[1]))<EPS) {printf("%.4f %.4f %.4f\n",dis(a[0],a[2])*0.5,(a[0].x+a[2].x)*0.5,(a[0].y+a[2].y)*0.5); return 0;}
int flag1=check(a[0],a[1]),flag2=check(a[0],a[2]);
if(flag1!=0 && flag2!=0){
Point tmp=a[0]; a[0]=a[1]; a[1]=tmp;
flag2=check(a[0],a[2]);
}
if(flag2!=0){
Point tmp=a[1]; a[1]=a[2]; a[2]=tmp;
int tm2=flag1; flag1=flag2; flag2=tm2;
}//line(a[0],a[1])為特殊或一般;line(a[0],a[2])為一般
double k2=(a[2].y-a[0].y)/(a[2].x-a[0].x);
double b2=a[0].y-a[0].x*k2;
double k4=(-1.0)/k2;
Point mp2=(Point){(a[0].x+a[2].x)*0.5,(a[0].y+a[2].y)*0.5};
double b4=mp2.y-mp2.x*k4;
if(flag1==-1){
Point ap; ap.y=(a[0].y+a[1].y)*0.5;
ap.x=(ap.y-b4)/k4;
printf("%.4f %.4f %.4f\n",dis(ap,a[0]),ap.x,ap.y);
}
else if(flag1==1){
Point ap; ap.x=(a[0].x+a[1].x)*0.5;
ap.y=k4*ap.x+b4;
printf("%.4f %.4f %.4f\n",dis(ap,a[0]),ap.x,ap.y);
}
else/*flag1==0*/{
double k1=(a[1].y-a[0].y)/(a[1].x-a[0].x);
double b1=a[0].y-a[0].x*k1;
double k3=(-1.0)/k1;
Point mp1=(Point){(a[0].x+a[1].x)*0.5,(a[0].y+a[1].y)*0.5};
double b3=mp1.y-mp1.x*k3;
Point ap; ap.x=(b4-b3)/(k3-k4); ap.y=k3*ap.x+b3;
printf("%.4f %.4f %.4f\n",dis(ap,a[0]),ap.x,ap.y);
}
return 0;
}
<法二>
設三角形三個頂點分別為(x1,y1),(x2,y2),(x3,y3),待求的圓心為(x,y)。
則顯然有以下方程組成立
(x-x1)^2+(y-y1)^2 = (x-x2)^2+(y-y2)^2 = (x-x3)^2+(y-y3)^2
化簡為
{2*(x2-x1)*x+2*(y2-y1)*y = -x1^2-y1^2+x2^2+y2^2
{
{2*(x3-x1)*x+2*(y3-y1)*y = -x1^2-y1^2+x3^2+y3^2
該二元一次方程組可以用克拉默法則方便求解。
這種做法不需要討論三條邊的種種位置關係,程式碼也比較短,在第二份標程中給出。
#include<stdio.h>
#include<math.h>
#define EPS 0.00000001
int n;
typedef struct {double x,y;}Point;
typedef Point Vector;
double sqr(double x){return x*x;}
double dis(Point a,Point b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
Vector Minus (Point a,Point b){return (Vector){a.x-b.x,a.y-b.y};}
double dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;};
Point a[3];
int main()
{
//freopen("01.in","r",stdin);
//freopen("09.out","w",stdout);
int i;
scanf("%d",&n);
for(i=0;i<n;++i) scanf("%lf%lf",&a[i].x,&a[i].y);
if(n==1) {printf("%.4f %.4f %.4f\n",0.0,a[0].x,a[0].y); return 0;}
if(n==2) {printf("%.4f %.4f %.4f\n",dis(a[0],a[1])*0.5,(a[0].x+a[1].x)*0.5,(a[0].y+a[1].y)*0.5); return 0;}
if(dot(Minus(a[1],a[0]),Minus(a[2],a[0]))<EPS) {printf("%.4f %.4f %.4f\n",dis(a[1],a[2])*0.5,(a[1].x+a[2].x)*0.5,(a[1].y+a[2].y)*0.5); return 0;}
else if(dot(Minus(a[1],a[2]),Minus(a[0],a[2]))<EPS) {printf("%.4f %.4f %.4f\n",dis(a[1],a[0])*0.5,(a[1].x+a[0].x)*0.5,(a[1].y+a[0].y)*0.5); return 0;}
else if(dot(Minus(a[0],a[1]),Minus(a[2],a[1]))<EPS) {printf("%.4f %.4f %.4f\n",dis(a[0],a[2])*0.5,(a[0].x+a[2].x)*0.5,(a[0].y+a[2].y)*0.5); return 0;}
double b[3],A[3][3];
A[1][1]=2.0*(a[1].x-a[0].x);
A[1][2]=2.0*(a[1].y-a[0].y);
b[1]=-a[0].x*a[0].x-a[0].y*a[0].y+a[1].x*a[1].x+a[1].y*a[1].y;
A[2][1]=2.0*(a[2].x-a[0].x);
A[2][2]=2.0*(a[2].y-a[0].y);
b[2]=-a[0].x*a[0].x-a[0].y*a[0].y+a[2].x*a[2].x+a[2].y*a[2].y;
double tmp=A[1][1]*A[2][2]-A[1][2]*A[2][1];
double tmp1=b[1]*A[2][2]-A[1][2]*b[2];
double tmp2=A[1][1]*b[2]-b[1]*A[2][1];
Point ans;
ans.x=tmp1/tmp;
ans.y=tmp2/tmp;
printf("%.4f %.4f %.4f\n",dis(ans,a[0]),ans.x,ans.y);
return 0;
}
感謝大家參加本場趣味賽,趣味賽評獎結果我們會在群內公佈,接下來還有兩場更為精彩的比賽,歡迎大家參加!