A.(Gym-12483A)
B.(Gym-12483B)
C.構造圖(Gym-12483C)
題意:給出一個樹,要求寫出每個節點的座標,使得相鄰節點之間的距離爲1,並且任何一對節點之間的距離最少爲$10^{-4}$,相鄰節點之間的距離與1的絕對誤差最多爲$10^{-6}$,不連接在同一節點的邊之間的距離至少爲$10^{-6}$,座標的絕對值不超過$3000$。
解:分配邊轉化爲分配角度$\theta$,那麼點的座標就是$(x+cos\theta,y+sin\theta)$,爲了避免交叉,利用樹的結構進行dfs,角度按照dfs的順序增大,這樣就可以保證邊不重疊了,實際上不用刻意的研究$10^{-4}和10^{-6}$,可以認爲這兩個數字就表示無窮小,也就是點重疊,邊交叉的情況。比賽的時候沒認真考慮邊交叉,就用了bfs,後來隊友也寫了一個,寫的dfs,但也wa了。賽後去看了一下別人的代碼,才突然意識到這個問題。隊友寫的dfs我也看了一下,發現裏面出了一個極小無比的錯誤,改掉就過了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#define maxn 1001
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
using namespace std;
int num,head[maxn];
struct node{
int to,pre;
}e[maxn*2];
void Insert(int from,int to){
e[++num].to=to;
e[num].pre=head[from];
head[from]=num;
}
struct point{
double x,y;
}p[maxn];
int n;
double Eps;
bool vis[maxn];
int cnt=-1;
void dfs(int now){
for(int i=head[now];i;i=e[i].pre){
int to=e[i].to;
if(!vis[to]){
vis[to]=1;
cnt++;
p[to].x=p[now].x+cos(Eps*cnt);
p[to].y=p[now].y+sin(Eps*cnt);
dfs(to);
}
}
}
int main(){
scanf("%d",&n);
Eps=(double)M_PI/(double)1000;
int x,y;
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
Insert(x,y);Insert(y,x);
}
p[1].x=0;p[1].y=0;
vis[1]=1;
dfs(1);
for(int i=1;i<=n;i++){
printf("%.15f %.15f\n",(double)p[i].x,(double)p[i].y);
}
return 0;
}
D.(Gym-12483D)
E.(Gym-12483E)
F.(Gym-12483F)
G.構造障礙(Gym-12483G)
題意:在一個平面上有一個小球,許多障礙物和一個洞(洞的座標爲(0,0)),將平板向一個方向傾斜,就可以使小球向這個方一直滾動,直到遇到障礙物或者進洞。題目給出一個包含LRUD的字符串,表示平板傾斜的方向序列,要求根據這個序列設計一種障礙物的擺放方法,使小球最後能順利進洞,不能滿足條件的輸出impossible。
解:規定小球從(0,0)開始滾動,最後根據最終的位置應該在(0,0),把所有的點進行平移。可以先判斷能夠產生impossible的情況,impossible實際上就是中途進洞,因爲最後一步移動要把小球移動到洞裏,所以如果有LRL,RLR,UDU,DUD這四種情況出現在最後三次操作中,就直接輸出impossible了。求路徑時,如果有RLRL這類情況,就可以只設置左右兩個障礙,如果出現RU這類情況,就把小球向U移兩格,設置新的障礙。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define maxn 10010 using namespace std; char s[21]; int n,cnt; bool flag; struct node{ int x,y; bool operator == (const node u)const{ if(x==u.x&&y==u.y)return 1; return 0; } bool operator < (const node u)const{ if(x!=u.x)return x<u.x; return y<u.y; } }ans[maxn]; int main(){ scanf("%s",s+1); n=strlen(s+1); if(n>=3){ if(!strcmp(s+n-2,"LRL"))flag=1; if(!strcmp(s+n-2,"RLR"))flag=1; if(!strcmp(s+n-2,"UDU"))flag=1; if(!strcmp(s+n-2,"DUD"))flag=1; } if(flag){ puts("impossible"); return 0; } int d=1; int x=0,y=0; for(int i=1;i<=n;i++){ if(s[i]=='R'){ x=d; ans[++cnt]={x+1,y}; } if(s[i]=='L'){ x=-d; ans[++cnt]={x-1,y}; } if(s[i]=='U'){ y=d; ans[++cnt]={x,y+1}; } if(s[i]=='D'){ y=-d; ans[++cnt]={x,y-1}; } if(i+1<=n){ if(s[i]=='L'&&s[i+1]=='R'); else if(s[i]=='R'&&s[i+1]=='L'); else if(s[i]=='U'&&s[i+1]=='D'); else if(s[i]=='D'&&s[i+1]=='U'); else d+=2; } } printf("%d %d\n",-x,-y); sort(ans+1,ans+cnt+1); n=unique(ans+1,ans+cnt+1)-ans-1; printf("%d\n",n); for(int i=1;i<=n;i++){ printf("%d %d\n",ans[i].x-x,ans[i].y-y); } return 0; }
H.(Gym-12483H)
題意:一共有n個位置,可以填入0或1,如果相鄰兩個數字不同,就稱爲有一個change,題目中指定b個位置只能爲0(約定第一個位置不指定,最後一個位置指定),其它位置填0或者1,使得恰好有c個change,要求寫出一種符合要求的01串。
解:可以發現如果在兩個0之間填1,無論如何都會增加偶數個change,而如果在第一個位置填了1,那麼無論如何都會增加奇數個1。所以可以通過c的奇偶性來判斷第一個位置應該填的數。然後根據剩下的需要滿足的change數,來順次填不一樣的數字。
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 500010
using namespace std;
int n,c,b,a[maxn];
int main(){
scanf("%d%d%d",&n,&c,&b);
memset(a,-1,sizeof(a));
int x;
for(int i=1;i<=b;i++){
scanf("%d",&x);
a[x]=0;
}
if(c%2==1){a[1]=1;}
else a[1]=0;
for(int i=2;i<=n;i++){
if(a[i]==-1){
if(c>0)a[i]=!a[i-1];
}
if(a[i]!=a[i-1])c--;
if(c<=0)break;
}
for(int i=1;i<=n;i++){
if(a[i]==-1)a[i]=0;
printf("%d",a[i]);
}
puts("");
return 0;
}
I.(Gym-12483I)
J.(Gym-12483J)
K.(Gym-12483K)