1.UVa1001.奶酪里的老鼠
大意就是一个三维空间中有n个洞,有两只老鼠在A和O两点,老鼠从A点出发,在奶酪中的移动速度为10米一个单位,在洞中是可以瞬间移动的,输入洞的圆心和半径,以及起点和终点的三维坐标,问最短时间。
隐式图建图,建立从起点到所有洞圆心的边,建立从终点到所有洞的边,边长为max(0,distance(A(或者O),Oi)-r[i]),再建立从起点到终点的边,边长为两点距离,再建立所有洞之间的边,边长为max(0,distance(Oi,Oj)-r[i]-r[j]),跑一遍最短路就行。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn=110;
const int maxm=110*110;
const double INF=0x3f3f3f3f;
struct Edge
{
int to;
int next;
double w;
}edges[maxm];
int head[maxn],tot;
void init()
{
memset(head,-1,sizeof(head));
tot=0;
}
void add_edges(int u,int v,double w)
{
edges[tot].to=v;
edges[tot].next=head[u];
edges[tot].w=w;
head[u]=tot++;
}
struct ball
{
double x,y,z,r;
ball(){};
ball(double x,double y,double z,double r)
{
this->x=x;
this->y=y;
this->z=z;
this->r=r;
}
}b[maxn];
struct HeapNode
{
double d;
int u;
HeapNode(double d,int u):d(d),u(u){}
bool operator <(const HeapNode &rhs)const
{
return d>rhs.d;
}
};
double dist[maxn];
int vis[maxn];
double Distance(ball a,ball b)
{
double temp=(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z);
return sqrt(temp);
}
void dijkstra(int s,int n)
{
priority_queue<HeapNode>Q;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n+2;i++)dist[i]=INF;
dist[s]=0;
Q.push(HeapNode(0,s));
while(!Q.empty())
{
HeapNode x=Q.top();Q.pop();
int u=x.u;
if(vis[u])continue;
vis[u]=1;
for(int i=head[u];i!=-1;i=edges[i].next)
{
int v=edges[i].to;
if(dist[v]>dist[u]+edges[i].w)
{
dist[v]=dist[u]+edges[i].w;
Q.push(HeapNode(dist[v],v));
}
}
}
}
int main()
{
int n;
int index=1;
while(scanf("%d",&n)!=EOF)
{
if(n==-1)break;
for(int i=2;i<=n+1;i++)
{
scanf("%lf%lf%lf%lf",&b[i].x,&b[i].y,&b[i].z,&b[i].r);
}
double sx,sy,sz;
double ex,ey,ez;
scanf("%lf%lf%lf",&sx,&sy,&sz);
scanf("%lf%lf%lf",&ex,&ey,&ez);
b[1]=ball(sx,sy,sz,0);
b[n+2]=ball(ex,ey,ez,0);
init();
//加边
//起点到所有洞
for(int i=2;i<=n+1;i++)
{
double dis=Distance(b[1],b[i]);
dis=dis-b[i].r;
if(dis<0)dis=0;
add_edges(1,i,dis*10);
add_edges(i,1,dis*10);
}
//终点到所有洞
for(int i=2;i<=n+1;i++)
{
double dis=Distance(b[n+2],b[i]);
dis=dis-b[i].r;
if(dis<0)dis=0;
add_edges(n+2,i,dis*10);
add_edges(i,n+2,dis*10);
}
//终点与起点
double dis0=Distance(b[1],b[n+2]);
add_edges(1,n+2,dis0*10);
add_edges(n+2,1,dis0*10);
//所有洞之间
for(int i=2;i<=n+1;i++)
{
for(int j=i+1;j<=n+1;j++)
{
double dis=Distance(b[i],b[j]);
dis=dis-b[i].r-b[j].r;
if(dis<0)dis=0;
add_edges(i,j,dis*10);
add_edges(j,i,dis*10);
}
}
dijkstra(1,n);
printf("Cheese %d: Travel time = %d sec\n",index++,(int)(dist[n+2]+0.5));
}
return 0;
}
2.牛客国庆集训派对day1——L
中文题目就不说大意了。。。一样的套路,就是三维变成了二维,注意这里将两条平行边当做两个节点就行,建边的时候距离就是点到直线的距离,和上题差不多,跑一遍最短路就行。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <cmath>
using namespace std;
const int maxn=1010;
const int maxm=1010*1010;
const double eps=1e-4;
const double INF=0x3f3f3f3f;
struct Edge
{
int to,next;
double w;
}edges[maxm];
int head[maxn],tot;
void init()
{
memset(head,-1,sizeof(head));
tot=0;
}
void add_edges(int u,int v,double w)
{
edges[tot].to=v;
edges[tot].w=w;
edges[tot].next=head[u];
head[u]=tot++;
}
struct HeapNode
{
double d;
int u;
HeapNode(double d,int u):d(d),u(u){}
bool operator < (const HeapNode &rhs)const
{
return d>rhs.d;
}
};
struct ball
{
double x,y,r;
ball(){};
ball(double x,double y,double r)
{
this->x=x;
this->y=y;
this->r=r;
}
}b[maxn];
double dist[maxn];
int vis[maxn];
void dijkstra(int s, int n)
{
priority_queue<HeapNode>Q;
memset(vis,0,sizeof(vis));
for(int i=0;i<=n+2;i++)dist[i]=INF;
dist[s]=0;
Q.push(HeapNode(0,s));
while(!Q.empty())
{
HeapNode x=Q.top();Q.pop();
int u=x.u;
if(vis[u])continue;
vis[u]=1;
for(int i=head[u];i!=-1;i=edges[i].next)
{
int v=edges[i].to;
if(!vis[v]&&dist[v]>dist[u]+edges[i].w)
{
dist[v]=dist[u]+edges[i].w;
Q.push(HeapNode(dist[v],v));
}
}
}
}
double Distance1(ball a,ball b)
{
double temp=fabs(a.x-b.x)*fabs(a.x-b.x)+fabs(a.y-b.y)*fabs(a.y-b.y);
return sqrt(temp);
}
//点到直线的距离
double Distance2(double A,double B,double C,double x0,double y0)
{
double temp1=fabs(A*x0+B*y0+C);
double temp2=sqrt(A*A+B*B);
return temp1/temp2;
}
int main()
{
int n;
double A,B,C1,C2;
std::ios::sync_with_stdio(false);
while(cin>>n>>A>>B>>C1>>C2)
{
init();
for(int i=2;i<=n+1;i++)
{
cin>>b[i].x>>b[i].y>>b[i].r;
}
double dis0=fabs(C1-C2)/sqrt(A*A+B*B);//两直线间的距离
//两直线间建边
add_edges(1,n+2,dis0);
add_edges(n+2,1,dis0);
//起点与所有圆建边
for(int i=2;i<=n+1;i++)
{
double dis=Distance2(A,B,C1,b[i].x,b[i].y);
dis=dis-b[i].r;
if(dis<0)dis=0;
add_edges(1,i,dis);
add_edges(i,1,dis);
}
//终点与所有圆建边
for(int i=2;i<=n+1;i++)
{
double dis=Distance2(A,B,C2,b[i].x,b[i].y);
dis=dis-b[i].r;
if(dis<0)dis=0;
add_edges(n+2,i,dis);
add_edges(i,n+2,dis);
}
//所有圆之间建边
for(int i=2;i<=n+1;i++)
{
for(int j=i+1;j<=n+1;j++)
{
double dis=Distance1(b[i],b[j]);
dis=dis-b[i].r-b[j].r;
if(dis<0)dis=0;
add_edges(i,j,dis);
add_edges(j,i,dis);
}
}
dijkstra(1,n);
cout<<dist[n+2]<<endl;
}
return 0;
}