1. 程式人生 > >牛客國慶集訓派對Day1 L New Game!(SPFA)

牛客國慶集訓派對Day1 L New Game!(SPFA)

題意

有兩條直線,n個圓,讓你從一條直線走到另外一條直線,問你最少需要花費多少消耗

這裡在線上、圓內、圓上走路都不會產生消耗,在其他位置上由S點走到T點消耗的體力為S和T的歐幾里得距離。

解析:

寫這道題我就想吐槽一下這道題噁心的卡常......

我一開始用最暴力的每一個點都遍歷一遍所有的點來建邊,結果T了.....

然後就開始瘋狂預處理優化,結果還是T.....

最後看了別人的程式碼,把那些預處理去掉,直接最暴力的列舉每一對點對建邊就可以了

這題好像還有用DP的,但是我搞不清楚它的原理,想一想好像有點問題

SPFA 323MS

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
typedef long long ll;
using namespace std;
 
const double eps=1e-9;
const int MAXN =1e3+10;
const double INF = 1e18+10;
 
typedef struct node
{
    ll x,y;
    ll r;
}node;
 
typedef struct point
{
    int x,y;
    double w;
    int nxt;
}point;
 
node con[MAXN],con2[MAXN],in12[MAXN];
int head[MAXN];
int cnt;
int num12,num,num2;
point edge[MAXN*MAXN*10];
 
void addedge(int u,int v,double w)
{
    edge[cnt].x=u;
    edge[cnt].y=v;
    edge[cnt].w=w;
    edge[cnt].nxt=head[u];
    head[u]=cnt++;
}
 
inline double caldis(ll a,ll b,ll c,ll x0,ll y0)
{
    double  ans=a*x0+b*y0+c;
    ans=ans<0?-ans:ans;
    return ans/sqrt(a*a+b*b);
}
 
 
 
inline double cirdis(ll x1,ll y1,ll r1,ll x2,ll y2,ll r2)
{
    double  d=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
 
    return d>r1+r2?d-(r1+r2):0;
}
 
inline double line2(ll a,ll b,ll c1,ll c2)
{
    double  ans=c1-c2>0?c1-c2:c2-c1;
    return ans/sqrt(a*a+b*b);
}
 
inline double dis_cirline(ll x,ll y,ll r,ll a,ll b,ll c)
{
    double ans=caldis(a,b,c,x,y);
    return ans>r?ans-r:0;
}
 
double d[MAXN];
 
 
 
struct noww{
    int x;
    double d;
    noww(){}
    noww(int a,double b){x=a;d=b;}
    bool operator < (const noww & a) const
    {
        if(d==a.d) return x<a.x;
        else return d > a.d;
    }
};
int tot;

double st;
 int t;

bool vis[MAXN];
queue<int> q;
void SPFA(int src){
 
    //memset(vis,0,sizeof(vis));
 
    for(int i=0;i<=t;i++) d[i]=st;
 
    d[src]=0;
 
 
 
    q.push(src);
 
    while(!q.empty()){
 
        int u=q.front();
 
        q.pop();
 
        vis[u]=0;
        for(int i=head[u];i!=-1;i=edge[i].nxt)
        {
            int v=edge[i].y;
            double tmp=d[u]+edge[i].w;
                if(d[v]>tmp){
                    d[v]=tmp;
                    if(!vis[v]){
                        vis[v]=true;
                        q.push(v);
                    }
 
                }
        }
 
        }
 
 
 
}
 
 
int main()
{
    int n;
    ll a,b,c1,c2;
    scanf("%d%lld%lld%lld%lld",&n,&a,&b,&c1,&c2);
    num12=num=num2=1;
    cnt=0;
    node tmp;
    double d1,d2;
    int flag=0;
    int s=0;
    st=line2(a,b,c1,c2);
 
    memset(head,-1,sizeof(head));
    for(int i=0;i<n;i++)
    {
        scanf("%lld%lld%lld",&tmp.x,&tmp.y,&tmp.r);
 
        con[num]=tmp;
        num++;
    }
    if(flag)
    {
        printf("0.000000\n");
        return 0;
    }
    t=num;
    addedge(s,t,st);
    for(int i=1;i<num;i++)
    {
        addedge(s,i,dis_cirline(con[i].x,con[i].y,con[i].r,a,b,c1));
        addedge(i,t,dis_cirline(con[i].x,con[i].y,con[i].r,a,b,c2));
        for(int j=i+1;j<num;j++)
        {
            if(i==j) continue;
            addedge(i,j,cirdis(con[i].x,con[i].y,con[i].r,con[j].x,con[j].y,con[j].r));
            addedge(j,i,cirdis(con[i].x,con[i].y,con[i].r,con[j].x,con[j].y,con[j].r));
        }
    }
    SPFA(s);
    printf("%.6lf\n",d[t]);
 
}

Dij 727ms 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
  
const double eps=1e-9;
const int MAXN =1e3+10;
const double INF = 1e18+10;
  
typedef struct node
{
    double x,y;
    double r;
}node;
  
typedef struct point
{
    int x,y;
    double w;
    int nxt;
}point;
  
node con[MAXN];
int head[MAXN];
int num,cnt;
point edge[MAXN*MAXN*2];
  
void addedge(int u,int v,double w)
{
    edge[cnt].x=u;
    edge[cnt].y=v;
    edge[cnt].w=w;
    edge[cnt].nxt=head[u];
    head[u]=cnt++;
}
  
inline double caldis(double a,double b,double c,double x0,double y0)
{
    double ans=a*x0+b*y0+c;
    ans=ans<0?-ans:ans;
    return ans/sqrt(a*a+b*b);
}
  
  
  
inline double cirdis(double x1,double y1,double r1,double x2,double y2,double r2)
{
    double d=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    if(d>r1+r2) return d-(r1+r2);
    else return 0;
}
  
inline double line2(double a,double b,double c1,double c2)
{
    double ans=c1-c2>0?c1-c2:c2-c1;
    return ans/sqrt(a*a+b*b);
}
  
inline double dis_cirline(double x,double y,double r,double a,double b,double c)
{
    double ans=caldis(a,b,c,x,y);
    if(ans>r) return ans-r;
    else return 0;
}
  
double dis[MAXN];
  
struct noww{
    int x;
    double d;
    noww(){}
    noww(int a,double b){x=a;d=b;}
    bool operator < (const noww & a) const
    {
        if(d==a.d) return x<a.x;
        else return d > a.d;
    }
};
  
  
void Dijkstra(int s)
{
    int i;
    for(i=0;i<=num;i++) dis[i]=INF;
    dis[s]=0;
    //用優先佇列優化
    priority_queue<noww> q;
    q.push(noww(s,dis[s]));
    while(!q.empty())
    {
        noww x=q.top();q.pop();
        for(i=head[x.x];i!=-1;i=edge[i].nxt)
        {
            if(dis[edge[i].y]>x.d+edge[i].w)
            {
                dis[edge[i].y]=x.d+edge[i].w;
                q.push(noww(edge[i].y,dis[edge[i].y]));
            }
        }
    }
}
  
  
  
int main()
{
    int n;
    double a,b,c1,c2;
    scanf("%d%lf%lf%lf%lf",&n,&a,&b,&c1,&c2);
    num=1;
    cnt=0;
    node tmp;
    double d1,d2;
    int flag=0;
    int s=0;
    double st=line2(a,b,c1,c2);
    int t;
    memset(head,-1,sizeof(head));
    for(int i=0;i<n;i++)
    {
        scanf("%lf%lf%lf",&tmp.x,&tmp.y,&tmp.r);
        con[num]=tmp;
        num++;
           
    }
    if(flag)
    {
        printf("0.000000\n");
        return 0;
    }
    t=num;
    addedge(s,t,st);
    for(int i=1;i<num;i++)
    {
        addedge(s,i,dis_cirline(con[i].x,con[i].y,con[i].r,a,b,c1));
        addedge(i,t,dis_cirline(con[i].x,con[i].y,con[i].r,a,b,c2));
        for(int j=i+1;j<num;j++)
        {
            if(i==j) continue;
            addedge(i,j,cirdis(con[i].x,con[i].y,con[i].r,con[j].x,con[j].y,con[j].r));
            addedge(j,i,cirdis(con[i].x,con[i].y,con[i].r,con[j].x,con[j].y,con[j].r));
        }
    }
    Dijkstra(s);
    printf("%.6lf\n",dis[t]);
  
}