您的位置:首页 > 运维架构

Gym 101308(ACM ICPC 2009–2010, Northeastern European Regional Contest)

2017-04-16 22:37 567 查看
PROBLEM A B D H ARE INCLUDED

Problem A. Asteroids

转自:http://www.cnblogs.com/kuangbin/archive/2012/09/12/2682588.html

题意&&思路:

           就是对两个凸包求重心到表面的最短距离。

代码:

/*
HDU 4273 Rescue
给一个三维凸包,求重心到表面的最短距离
模板题:三维凸包+多边形重心+点面距离
*/

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<stdlib.h>
using namespace std;
const int MAXN=550;
const double eps=1e-8;

struct Point
{
double x,y,z;
Point(){}

Point(double xx,double yy,double zz):x(xx),y(yy),z(zz){}

//两向量之差
Point operator -(const Point p1)
{
return Point(x-p1.x,y-p1.y,z-p1.z);
}

//两向量之和
Point operator +(const Point p1)
{
return Point(x+p1.x,y+p1.y,z+p1.z);
}

//叉乘
Point operator *(const Point p)
{
return Point(y*p.z-z*p.y,z*p.x-x*p.z,x*p.y-y*p.x);
}

Point operator *(double d)
{
return Point(x*d,y*d,z*d);
}

Point operator / (double d)
{
return Point(x/d,y/d,z/d);
}

//点乘
double  operator ^(Point p)
{
return (x*p.x+y*p.y+z*p.z);
}
};

struct CH3D
{
struct face
{
//表示凸包一个面上的三个点的编号
int a,b,c;
//表示该面是否属于最终凸包上的面
bool ok;
};
//初始顶点数
int n;
//初始顶点
Point P[MAXN];
//凸包表面的三角形数
int num;
//凸包表面的三角形
face F[8*MAXN];
//凸包表面的三角形
int g[MAXN][MAXN];
//向量长度
double vlen(Point a)
{
return sqrt(a.x*a.x+a.y*a.y+a.z*a.z);
}
//叉乘
Point cross(const Point &a,const Point &b,const Point &c)
{
return Point((b.y-a.y)*(c.z-a.z)-(b.z-a.z)*(c.y-a.y),
(b.z-a.z)*(c.x-a.x)-(b.x-a.x)*(c.z-a.z),
(b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x)
);
}
//三角形面积*2
double area(Point a,Point b,Point c)
{
return vlen((b-a)*(c-a));
}
//四面体有向体积*6
double volume(Point a,Point b,Point c,Point d)
{
return (b-a)*(c-a)^(d-a);
}
//正:点在面同向
double dblcmp(Point &p,face &f)
{
Point m=P[f.b]-P[f.a];
Point n=P[f.c]-P[f.a];
Point t=p-P[f.a];
return (m*n)^t;
}
void deal(int p,int a,int b)
{
int f=g[a];//搜索与该边相邻的另一个平面
face add;
if(F[f].ok)
{
if(dblcmp(P[p],F[f])>eps)
dfs(p,f);
else
{
add.a=b;
add.b=a;
add.c=p;//这里注意顺序,要成右手系
add.ok=true;
g[p][b]=g[a][p]=g[b][a]=num;
F[num++]=add;
}
}
}
void dfs(int p,int now)//递归搜索所有应该从凸包内删除的面
{
F[now].ok=0;
deal(p,F[now].b,F[now].a);
deal(p,F[now].c,F[now].b);
deal(p,F[now].a,F[now].c);
}
bool same(int s,int t)
{
Point &a=P[F[s].a];
Point &b=P[F[s].b];
Point &c=P[F[s].c];
return fabs(volume(a,b,c,P[F[t].a]))<eps &&
fabs(volume(a,b,c,P[F[t].b]))<eps &&
fabs(volume(a,b,c,P[F[t].c]))<eps;
}
//构建三维凸包
void create()
{
int i,j,tmp;
face add;

num=0;
if(n<4)return;
//**********************************************
//此段是为了保证前四个点不共面
bool flag=true;
for(i=1;i<n;i++)
{
if(vlen(P[0]-P[i])>eps)
{
swap(P[1],P[i]);
flag=false;
break;
}
}
if(flag)return;
flag=true;
//使前三个点不共线
for(i=2;i<n;i++)
{
if(vlen((P[0]-P[1])*(P[1]-P[i]))>eps)
{
swap(P[2],P[i]);
flag=false;
break;
}
}
if(flag)return;
flag=true;
//使前四个点不共面
for(int i=3;i<n;i++)
{
if(fabs((P[0]-P[1])*(P[1]-P[2])^(P[0]-P[i]))>eps)
{
swap(P[3],P[i]);
flag=false;
break;
}
}
if(flag)return;
//*****************************************
for(i=0;i<4;i++)
{
add.a=(i+1)%4;
add.b=(i+2)%4;
add.c=(i+3)%4;
add.ok=true;
if(dblcmp(P[i],add)>0)swap(add.b,add.c);
g[add.a][add.b]=g[add.b][add.c]=g[add.c][add.a]=num;
F[num++]=add;
}
for(i=4;i<n;i++)
{
for(j=0;j<num;j++)
{
if(F[j].ok&&dblcmp(P[i],F[j])>eps)
{
dfs(i,j);
break;
}
}
}
tmp=num;
for(i=num=0;i<tmp;i++)
if(F[i].ok)
F[num++]=F[i];

}
//表面积
double area()
{
double res=0;
if(n==3)
{
Point p=cross(P[0],P[1],P[2]);
res=vlen(p)/2.0;
return res;
}
for(int i=0;i<num;i++)
res+=area(P[F[i].a],P[F[i].b],P[F[i].c]);
return res/2.0;
}
double volume()
{
double res=0;
Point tmp(0,0,0);
for(int i=0;i<num;i++)
res+=volume(tmp,P[F[i].a],P[F[i].b],P[F[i].c]);
return fabs(res/6.0);
}
//表面三角形个数
int triangle()
{
return num;
}
//表面多边形个数
int polygon()
{
int i,j,res,flag;
for(i=res=0;i<num;i++)
{
flag=1;
for(j=0;j<i;j++)
if(same(i,j))
{
flag=0;
break;
}
res+=flag;
}
return res;
}
//三维凸包重心
Point barycenter()
{
Point ans(0,0,0),o(0,0,0);
double all=0;
for(int i=0;i<num;i++)
{
double vol=volume(o,P[F[i].a],P[F[i].b],P[F[i].c]);
ans=ans+(o+P[F[i].a]+P[F[i].b]+P[F[i].c])/4.0*vol;
all+=vol;
}
ans=ans/all;
return ans;
}
//点到面的距离
double ptoface(Point p,int i)
{
return fabs(volume(P[F[i].a],P[F[i].b],P[F[i].c],p)/vlen((P[F[i].b]-P[F[i].a])*(P[F[i].c]-P[F[i].a])));
}
};
CH3D hull;
int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
while(scanf("%d",&hull.n)==1)
{
for(int i=0;i<hull.n;i++)
{
scanf("%lf%lf%lf",&hull.P[i].x,&hull.P[i].y,&hull.P[i].z);
}
hull.create();
Point p=hull.barycenter();
double ans1=1e20;
for(int i=0;i<hull.num;i++)
{
ans1=min(ans1,hull.ptoface(p,i));
}

scanf("%d",&hull.n);
for(int i=0;i<hull.n;i++)
{
scanf("%lf%lf%lf",&hull.P[i].x,&hull.P[i].y,&hull.P[i].z);
}
hull.create();
p=hull.barycenter();
double ans2=1e20;
for(int i=0;i<hull.num;i++)
{
ans2=min(ans2,hull.ptoface(p,i));
}

printf("%.5f\n",ans1+ans2);
}
return 0;
}
[b]Problem B. Business Center

题意:

          给你好多电梯,每个电梯只有两个按钮,上a层和下b层,问选一个电梯,经过n次按按钮,能到达的最低楼层

代码:

#include <iostream>
#include <cstdio>

using namespace std;

int main()
{
freopen("business.in","r",stdin);
freopen("business.out","w",stdout);
int n,m,a,b,c,mi,t;
while(cin>>n>>m)
{
mi=0x3f3f3f3f;
for(int i=1;i<=m;i++)
{
cin>>a>>b;
c=n%(a+b);
t=0;
if(c==0)
t=b+a;
for(int j=1;j<=c;j++)
{
if(t>b)
t-=b;
else
t+=a;
}
mi=min(t,mi);
}
cout<<mi<<endl;
}
return 0;
}
Problem D. Database

题意:

            给一个数据库,查找是否存在(r1,c1)=(r2,c1) && (r1,c2)=(r2,c2),即:不同的二行,对应二列字符串相同


思路:

            紫书收录了此题,主要是对字符串和map的使用

代码:

#include <iostream>
#include <cstring>
#include <string>
#include <map>
#include <cstdio>

using namespace std;

int main()
{
freopen("database.in","r",stdin);
freopen("database.out","w",stdout);
ios::sync_with_stdio(false);
int m,n,t1,t2,x,y,head[10005];
string str[10005][15],a;
int flag;
map<string,int> ok;
map<int,int> w;
while(cin>>m>>n)
{
cin.get();
w.clear();
flag=1;
for(int i=1;i<=m;i++)
{
getline(cin,a);
t1=t2=0;
for(int j=1;j<n;j++)
{
while(1)
{
if(a[t2]==',')
break;
t2++;
}
str[i][j]=a.substr(t1,t2-t1);
t1=t2+1;
t2++;
}
str[i]
=a.substr(t2,a.size()-t2);
}
for(int i=1;i<=n;i++)
{
ok.clear();
memset(head,-1,sizeof(head));
for(int j=1;j<=m;j++)
{
if(!ok[str[j][i]])
ok[str[j][i]]=j;
else
{
head[j]=ok[str[j][i]];
for(int k=head[j];k!=-1;k=head[k])
{
if(!w[j*10001+k])
w[j*10001+k]=i;
else
{
cout<<"NO"<<endl;
flag=0;
cout<<k<<" "<<j<<endl;
cout<<w[j*10001+k]<<" "<<i<<endl;
goto P;
}
}
ok[str[j][i]]=j;
}
}
}
P:
if(flag)
cout<<"YES"<<endl;
}
return 0;
}


Problem H. Headshot

题意:

          俄罗斯轮盘赌游戏,已知第一发是空枪,问如何操作,才获得最大的生存概率。

思路:

          水题,统计下转与不转的概率即可

代码:
#include <bits/stdc++.h>
using namespace std;

int main(){
freopen("headshot.in","r",stdin);
freopen("headshot.out","w",stdout);
string str;
while(cin>>str){
int n=str.size();
double die=0,alive=0,numz=0,numo=0;
for(int i=0;i<n;i++){
if(str[i]=='0'){
numz++;
if(str[(i+1)%n]=='1')
die++;
else
alive++;
}else{
numo++;
}
}
double chance1=alive/(alive+die);
double chance2=numz/(numz+numo);
if(chance2>chance1){
cout<<"ROTATE"<<endl;
continue;
}else if(chance2==chance1){
cout<<"EQUAL"<<endl;
}else{
cout<<"SHOOT"<<endl;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐