http://www.lydsy.com:808/JudgeOnline/problem.php?id=3564
思路:如果裸着做会很麻烦,所以我们需要进行一个简单的预处理。和增幅仪的旋转角度相反,将所有点顺时针旋转a度,然后将所有点的横坐标缩小p倍。然后就可以套用最小圆覆盖的模板做了,这里我用的是随机增量法。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #include <cmath> #define PI 3.14159265358979323846 #define MAXN 510000 #define EPS (1E-20) using namespace std; struct Point { double x,y; Point(double xx=0,double yy=0) { x=xx; y=yy; } Point operator-(Point a) { return Point(x-a.x,y-a.y); } Point operator+(Point a) { return Point(x+a.x,y+a.y); } double operator*(Point a) { return x*a.y-y*a.x; } Point operator*(double t) { return Point(x*t,y*t); } Point operator/(double t) { return Point(x/t,y/t); } Point rotate(double ang) //绕原点顺时针旋转ang度 { return Point(x*cos(ang)+y*sin(ang),-x*sin(ang)+y*cos(ang)); } Point verl() { return Point(-y,x); } }dots[MAXN]; int n; int dcmp(double x) //x>0返回1,x<0返回-1,x==0返回0 { if(fabs(x)<EPS) return 0; if(x>EPS) return 1; return -1; } double dist(Point a,Point b) //求点a到点b距离 { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } Point cross(Point a,Point b,Point c,Point d) //求向量ab叉乘向量cd { double s1=(d-a)*(c-a); double s2=(c-b)*(d-b); return (a*s2+b*s1)/(s1+s2); } Point cal(Point A,Point B,Point C) { Point ret; double a1=B.x-A.x,b1=B.y-A.y,c1=(a1*a1+b1*b1)/2; double a2=C.x-A.x,b2=C.y-A.y,c2=(a2*a2+b2*b2)/2; double d=a1*b2-a2*b1; ret.x=A.x+(c1*b2-c2*b1)/d; ret.y=A.y+(a1*c2-a2*c1)/d; return ret; } int main() { double ang,scale; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lf%lf",&dots[i].x,&dots[i].y); scanf("%lf%lf",&ang,&scale); ang=ang/180*PI; for(int i=1;i<=n;i++) { dots[i]=dots[i].rotate(ang); dots[i].x/=scale; } double r=0; //r=三角形的外接圆半径 Point c=dots[1]; for(int i=2;i<=n;i++) { if(dist(dots[i],c)>r+EPS) { c=dots[i]; r=0; for(int j=1;j<i;j++) { if(dist(dots[j],c)>r+EPS) { c=(dots[i]+dots[j])/2; r=dist(dots[j],c); for(int k=1;k<j;k++) { if(dist(dots[k],c)>r+EPS) { c=cal(dots[i],dots[j],dots[k]); r=dist(dots[i],c); } } } } } } printf("%.3lf\n",r); return 0; }
http://www.lydsy.com:808/JudgeOnline/problem.php?id=3566
思路:树形DP,首先我们需要知道一个概率的公式,对于两个相互独立的事件A、B,P(A+B)=P(A)+P(B)-P(AB)。每个点都给它们的所有儿子贡献了一部分概率,第一次DFS时,我们需要求出每个点u的每个儿子v的充电概率P'(v)=P(v)+[P(u)*p(edge)]-[P(u)*p(edge)]*P(v)。由于第一次DFS时会混进重复计算的概率(因为父亲节点给本节点的概率不能被算进本节点给儿子节点的概率),所以要再进行一次DFS,去除掉重复的概率。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #include <cmath> #define MAXN 1001000 #define EPS (1E-6) using namespace std; struct edge { int u,v,next; double p; //边的导电概率 }edges[MAXN]; int head[MAXN],nCount=0; double pNode[MAXN]; //直接通电的概率 double f[MAXN]; double ans=0; void AddEdge(int U,int V,double P) { edges[++nCount].u=U; edges[nCount].v=V; edges[nCount].p=P; edges[nCount].next=head[U]; head[U]=nCount; } void dfs1(int u,int fa) //从点u开始dfs,u的父亲是fa { for(int p=head[u];p!=-1;p=edges[p].next) { int v=edges[p].v; if(v==fa) continue; dfs1(v,u); pNode[u]=pNode[u]+pNode[v]*edges[p].p-pNode[u]*edges[p].p*pNode[v]; } } bool dcmp(double a) { return fabs(a-0)<EPS; } void dfs2(int u,int fa) { ans+=f[u]; for(int p=head[u];p!=-1;p=edges[p].next) { int v=edges[p].v; if(v==fa) continue; double tmp=(1-pNode[v]*edges[p].p); if(dcmp(tmp)) //tmp==0 f[v]=1.0; else { double y=(double)(f[u]-pNode[v]*edges[p].p)/(double)(1-pNode[v]*edges[p].p); f[v]=pNode[v]+y*edges[p].p-pNode[v]*y*edges[p].p; } dfs2(v,u); } } int main() { int n; scanf("%d",&n); memset(head,-1,sizeof(head)); for(int i=1;i<n;i++) { int u,v,p; scanf("%d%d%d",&u,&v,&p); AddEdge(u,v,(double)p/(double)100); AddEdge(v,u,(double)p/(double)100); } for(int i=1;i<=n;i++) { scanf("%lf",&pNode[i]); pNode[i]/=100; } dfs1(1,-1); f[1]=pNode[1]; dfs2(1,-1); printf("%.6f\n",ans); return 0; }
http://www.lydsy.com:808/JudgeOnline/problem.php?id=3565
http://www.lydsy.com:808/JudgeOnline/problem.php?id=3562
http://www.lydsy.com:808/JudgeOnline/problem.php?id=3553
http://www.lydsy.com:808/JudgeOnline/problem.php?id=3554