tkdsheep-ZOJ2318

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

{{{
给出n个圆形岛屿的坐标以及半径,你乘坐着一艘船,这个船也是一个圆,船的初始坐标和半径也会给出,问能不能驾驶船脱离这些圆形小岛的包围

首先将所有圆平移,使船的圆心在原点上,然后把所有圆的半径加上船的半径,这样船就变成了一个点

对于两个【相交】的圆,连接圆心构成一条线段,那么船肯定不能穿过这些线段,所以题目变成了给出很多线段,问能不能找到一个包围原点的多边形

接下来的具体做法在shi哥的解体报告里说的比较清楚了,但我很土,一开始没搞懂有向角是什么东西。。也明白为什么要spfa求个最短路。。

实际上有向角说形象点就是判断顺时针还是逆时针,比如圆心i和圆心j,如果j在i的顺时针方向,则i到j的边权值为正,j到i的边权值为负,逆时针类似

总之就是方向不同,则权值的正负要对应上,判方向可以用叉积

然后spfa并不是为了做最短路,而是单纯判个负环而已,因为有负环就说明有多条线段连通构成了-2Pi的多边形

另外此题精度要求高,需要eps,对于相切的圆,点是依然可以从那条缝中穿过的
}}}

{{{

#include <iostream>
#include <queue>
#include <cmath>
#include <cstdio>
#include <set>
//#include <map>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <cassert>
#define MAX 1000000000
#define eps 1e-10
using namespace std;
//Never lose hope~ For the dream 


double x[300];
double y[300];
double r[300];
double l[300];//每个圆心到原点的距离 
struct node
{
    int x;
    double len;
};

vector <node> e[300];//edge
bool in[300];
int c[300];
double d[300];


int main()
{
    int re,i,j,k;
    double X,Y,len,R;
    node ss,tt; 
    cin>>re;
    while(re--)
    {

        int n;
        cin>>n;
        for(i=0;i<n;i++)
        {
            e[i].clear();
            cin>>x[i]>>y[i]>>r[i];
        }
        cin>>X>>Y>>R;
        for(i=0;i<n;i++)
        {
            x[i]-=X;
            y[i]-=Y;
            r[i]+=R;
            l[i]=sqrt(x[i]*x[i]+y[i]*y[i]); 
        }

        for(i=0;i<n;i++)
        for(j=i+1;j<n;j++)
        {
            double len=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
            if(len+eps>r[i]+r[j])//不相交,注意精度 
            continue;

            double chaji=x[i]*y[j]-x[j]*y[i];
            double angle=acos((l[i]*l[i]+l[j]*l[j]-len*len)/2/l[i]/l[j]);


            if(chaji>=0)//j在i的顺时针方向
            {
                ss.x=j;
                ss.len=angle;
                e[i].push_back(ss);
                ss.x=i;
                ss.len=-angle;
                e[j].push_back(ss);      
            }
            else
            {
                ss.x=j;
                ss.len=-angle;
                e[i].push_back(ss);
                ss.x=i;
                ss.len=angle;
                e[j].push_back(ss);
            } 
        }

        queue <int> q;
        for(i=0;i<n;i++)
        { 
            q.push(i);
            in[i]=true; 
            d[i]=c[i]=0;
        }

        bool ff=true;

        while(!q.empty())
        {
            ss.x=q.front();
            q.pop();
            in[ss.x]=false;
            c[ss.x]++;
            if(c[ss.x]>n)
            {
                ff=false;
                break;
            }
            for(i=0;i<e[ss.x].size();i++)
            {
                tt.x=e[ss.x][i].x;
                tt.len=d[ss.x]+e[ss.x][i].len;
                if(tt.len+eps<d[tt.x])//注意精度 
                {
                    d[tt.x]=tt.len;
                    if(!in[tt.x])
                    {
                        in[tt.x]=true;
                        q.push(tt.x);
                    }
                }

            }
        }

        if(ff)
        cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
        if(re)
        cout<<endl;

    }
    return 0;
}

}}}
给出n个圆形岛屿的坐标以及半径,你乘坐着一艘船,这个船也是一个圆,船的初始坐标和半径也会给出,问能不能驾驶船脱离这些圆形小岛的包围
首先将所有圆平移,使船的圆心在原点上,然后把所有圆的半径加上船的半径,这样船就变成了一个点
对于两个【相交】的圆,连接圆心构成一条线段,那么船肯定不能穿过这些线段,所以题目变成了给出很多线段,问能不能找到一个包围原点的多边形
接下来的具体做法在shi哥的解体报告里说的比较清楚了,但我很土,一开始没搞懂有向角是什么东西。。也明白为什么要spfa求个最短路。。
实际上有向角说形象点就是判断顺时针还是逆时针,比如圆心i和圆心j,如果j在i的顺时针方向,则i到j的边权值为正,j到i的边权值为负,逆时针类似
总之就是方向不同,则权值的正负要对应上,判方向可以用叉积
然后spfa并不是为了做最短路,而是单纯判个负环而已,因为有负环就说明有多条线段连通构成了-2Pi的多边形
另外此题精度要求高,需要eps,对于相切的圆,点是依然可以从那条缝中穿过的
#include <iostream>
#include <queue>
#include <cmath>
#include <cstdio>
#include <set>
//#include <map>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <cassert>
#define MAX 1000000000
#define eps 1e-10
using namespace std;
//Never lose hope~ For the dream 
double x[300];
double y[300];
double r[300];
double l[300];//每个圆心到原点的距离 
struct node
{
    int x;
    double len;
};
vector <node> e[300];//edge
bool in[300];
int c[300];
double d[300];
int main()
{
    int re,i,j,k;
    double X,Y,len,R;
    node ss,tt; 
    cin>>re;
    while(re--)
    {
        int n;
        cin>>n;
        for(i=0;i<n;i++)
        {
            e[i].clear();
            cin>>x[i]>>y[i]>>r[i];
        }
        cin>>X>>Y>>R;
        for(i=0;i<n;i++)
        {
            x[i]-=X;
            y[i]-=Y;
            r[i]+=R;
            l[i]=sqrt(x[i]*x[i]+y[i]*y[i]); 
        }
        for(i=0;i<n;i++)
        for(j=i+1;j<n;j++)
        {
            double len=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
            if(len+eps>r[i]+r[j])//不相交,注意精度 
            continue;
            double chaji=x[i]*y[j]-x[j]*y[i];
            double angle=acos((l[i]*l[i]+l[j]*l[j]-len*len)/2/l[i]/l[j]);
            if(chaji>=0)//j在i的顺时针方向
            {
                ss.x=j;
                ss.len=angle;
                e[i].push_back(ss);
                ss.x=i;
                ss.len=-angle;
                e[j].push_back(ss);      
            }
            else
            {
                ss.x=j;
                ss.len=-angle;
                e[i].push_back(ss);
                ss.x=i;
                ss.len=angle;
                e[j].push_back(ss);
            } 
        }
        queue <int> q;
        for(i=0;i<n;i++)
        { 
            q.push(i);
            in[i]=true; 
            d[i]=c[i]=0;
        }
        bool ff=true;
        while(!q.empty())
        {
            ss.x=q.front();
            q.pop();
            in[ss.x]=false;
            c[ss.x]++;
            if(c[ss.x]>n)
            {
                ff=false;
                break;
            }
            for(i=0;i<e[ss.x].size();i++)
            {
                tt.x=e[ss.x][i].x;
                tt.len=d[ss.x]+e[ss.x][i].len;
                if(tt.len+eps<d[tt.x])//注意精度 
                {
                    d[tt.x]=tt.len;
                    if(!in[tt.x])
                    {
                        in[tt.x]=true;
                        q.push(tt.x);
                    }
                }
            }
        }
        if(ff)
        cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
        if(re)
        cout<<endl;
    }
    return 0;
}