luogu P1027 Car的旅行路线
题面传送门
显然这是一道\(SPFA\)水题,难点在建边。
题目中给三个点求另一个点,那么只要找到对角线,然后把另一个点对称过去就好了。
代码实现:
#include<cstdio>
#include<queue>
#include<cmath>
#include<cstring>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,x[139][5],y[139][4],h[539],head,ans,tot,pus,sx,sy,sz,now,cur,ts,a,b,t[139],s;
double d[539];
struct yyy {
int to;
double w;
int z;
}f[80039],tmp;
inline void add(int x,int y,double z) {
f[++head]=(yyy) {
y,z,h[x]
};
h[x]=head;
}
queue<int> q;
int main() {
register int i,j,k,sh;
scanf("%d",&s);
while(s--) {
head=0;
memset(h,-1,sizeof(h));
for(i=1; i<=500; i++) d[i]=1e9;
scanf("%d%d%d%d",&n,&ts,&a,&b);
for(i=1; i<=n; i++) {
for(j=1; j<=3; j++)scanf("%d%d",&x[i][j],&y[i][j]);
ans=0;
for(j=1; j<=3; j++) {
for(k=j+1; k<=3; k++) {
if(sqrt((x[i][j]-x[i][k])*(x[i][j]-x[i][k])+(y[i][j]-y[i][k])*(y[i][j]-y[i][k]))>ans) {
ans=sqrt((x[i][j]-x[i][k])*(x[i][j]-x[i][k])+(y[i][j]-y[i][k])*(y[i][j]-y[i][k]));
x[i][4]=x[i][j]+x[i][k]-x[i][6-k-j];
y[i][4]=y[i][j]+y[i][k]-y[i][6-k-j];
}
}
}
scanf("%d",&t[i]);
for(j=1; j<=4; j++) {
for(k=j+1; k<=4; k++) {
add(i*4-4+j,i*4-4+k,sqrt((x[i][j]-x[i][k])*(x[i][j]-x[i][k])+(y[i][j]-y[i][k])*(y[i][j]-y[i][k]))*t[i]);
add(i*4-4+k,i*4-4+j,sqrt((x[i][j]-x[i][k])*(x[i][j]-x[i][k])+(y[i][j]-y[i][k])*(y[i][j]-y[i][k]))*t[i]);
}
}
}
for(i=1; i<=n; i++) {
for(j=1; j<=4; j++) {
for(k=i+1; k<=n; k++) {
for(sh=1; sh<=4; sh++) {
add(i*4-4+j,k*4-4+sh,ts*sqrt((x[i][j]-x[k][sh])*(x[i][j]-x[k][sh])+(y[i][j]-y[k][sh])*(y[i][j]-y[k][sh])));
add(k*4-4+sh,i*4-4+j,ts*sqrt((x[i][j]-x[k][sh])*(x[i][j]-x[k][sh])+(y[i][j]-y[k][sh])*(y[i][j]-y[k][sh])));
}
}
}
}
d[a*4-3]=d[a*4-1]=d[a*4-2]=d[a*4]=0;
q.push(a*4-3);
q.push(a*4-1);
q.push(a*4-2);
q.push(a*4);
while(!q.empty()) {
now=q.front();
//printf("%d\n",now);
q.pop();
cur=h[now];
while(cur!=-1) {
tmp=f[cur];
if(d[tmp.to]>d[now]+tmp.w) d[tmp.to]=d[now]+tmp.w,q.push(tmp.to);
cur=tmp.z;
}
}
printf("%.1lf\n",min(min(d[b*4-3],d[b*4-2]),min(d[b*4-1],d[b*4])));
}
}