牛客國慶集訓派對Day1 L New Game!(SPFA)
阿新 • • 發佈:2018-12-13
題意:
有兩條直線,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]); }