UVA1001+牛客国庆集训派对——隐式图建图

1.UVa1001.奶酪里的老鼠

题目链接:https://vjudge.net/contest/213916#problem/B

大意就是一个三维空间中有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

题目链接:https://www.nowcoder.com/acm/contest/201/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;
}

猜你喜欢

转载自blog.csdn.net/Q755100802/article/details/82924592