D. Gifts by the List
给的图是若干棵树,对每棵树dfs一次即可解决。如果有解,每个人送礼的对象一定是自己的祖先,这在dfs时可以顺便判断。然后就是每个人送礼对象,不能是他祖先送礼对象的真祖先。
每个人的送礼对象如果和父亲的送礼对象相同则不管,若是父亲送礼对象的后代则加到前面去。。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
vector<int> G[100010];
int a[100010];
bool vis[100010];
int indeg[100010];
list<int> ans;
bool ok = 1;
int dep[100010];
void dfs(int u,int pre){
vis[u] = 1;
if(vis[a[u]] == 0){
ok=0;
return;
}
if(pre!=-1){
if(dep[a[u]]<dep[pre] && a[u]!=a[pre]){
ok=0;
return;
}
if(dep[a[u]]>dep[pre]){
ans.push_front(a[u]);
}
}
int sz = G[u].size();
for(int i=0;i<sz;i++){
int v = G[u][i];
dep[v] = dep[u]+1;
dfs(v,u);
}
vis[u] = 0;
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
indeg[v]++;
}
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
if(indeg[i] == 0){
if(a[i]!=i){
ok = 0;
break;
}
ans.push_back(i);
dfs(i,-1);
}
}
if(ok){
cout<<ans.size()<<endl;
for(int i:ans){
printf("%d\n",i);
}
}else{
cout<<-1<<endl;
}
return 0;
}
E. Runaway to a Shadow
计算几何题,只需要用到一些基本的几何知识。首先判断一下
t=0
时刻虫子是否已经被盖住,如果是答案就是1。
对于每个盘子,可以用反正切算出圆心的方向,然后利用勾股定理/余弦定理算出覆盖的角度的范围。把所有角度范围做一次去重,看看占比即可得解。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 100010;
const double PI = 3.14159265358979323846264338327950288;
const double eps = 1e-6;
double x[maxn];
double y[maxn];
double r[maxn];
double dist(double x1,double y1,double x2,double y2){
return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
}
double dist2(double x1,double y1,double x2,double y2){
return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}
struct Seg{
double s,t;
bool operator<(const Seg &other)const{
return s<other.s;
}
}segs[maxn<<1];
bool ban[maxn<<1];
int main(){
double x0,y0,v,t;
cin>>x0>>y0>>v>>t;
int n;
cin>>n;
for(int i=0;i<n;i++){
scanf("%lf%lf%lf",&x[i],&y[i],&r[i]);
}
//是否已经盖住
for(int i=0;i<n;i++){
if(dist2(x[i],y[i],x0,y0)<=r[i]*r[i]){
printf("1.0000000000\n");
return 0;
}
}
int k = 0;
double R = v*t;
for(int i=0;i<n;i++){
//圆心连线角
double deg = atan2(y[i]-y0,x[i]-x0);
if(deg<0){
deg+=2*PI;
}
if(dist2(x[i],y[i],x0,y0) - r[i]*r[i] <= R*R){ //两点连线平方 - 盘子半径平方 <= vt平方
//张角 (勾股定理)
double deg2 = asin(r[i]/dist(x[i],y[i],x0,y0));
segs[k].s = deg-deg2;
segs[k].t = deg+deg2;
k++;
}else if(dist(x[i],y[i],x0,y0) < R+r[i]){
double dis = dist(x[i],y[i],x0,y0);
//张角 (余弦定理)
double deg2 = acos((R*R + dis*dis - r[i]*r[i])/(2.0*R*dis));
segs[k].s = deg-deg2;
segs[k].t = deg+deg2;
k++;
}
}
//处理越界
for(int i=0;i<k;i++){
if(segs[i].s<0){
segs[k].s=segs[i].s+2*PI;
segs[k].t=2*PI;
k++;
segs[i].s=0;
}else if(segs[i].t>2*PI){
segs[k].s=0;
segs[k].t=segs[i].t-2*PI;
k++;
segs[i].t=2*PI;
}
}
sort(segs,segs+k);
for(int i=1;i<k;i++){
if(segs[i].s<segs[i-1].t){
ban[i-1] = 1;
segs[i].s = segs[i-1].s;
segs[i].t = max(segs[i-1].t,segs[i].t);
}
}
double sum = 0;
for(int i=0;i<k;i++){
if(ban[i])continue;
sum+=segs[i].t-segs[i].s;
}
double ans = sum/(2.0*PI);
printf("%.10f\n",ans);
return 0;
}