洛谷P1027题解

首先,让我骂一句那没事找事的Car
还取一个那么奇怪的名字
看到这个题,恕我直言,我们明显可以看出这是一道图的最短路问题。由于这个题的数据范围很小(s只有100),所以在这里我们选取时间复杂度为O(n^3)的Floyd主要是好写
相信大家都想得到这些,其实这道题最大的难点在预处理所以我刚才说了一大堆废话,针对他给出的每个城市,我们应该如何处理呢?
首先是读入
 1 int a,b;
 2  scanf("%d%d%d%d",&n,&tf,&a,&b);
 3  for(int i=1;i<=4*n;i++)
 4    for(int j=1;j<=4*n;j++)
 5       e[i][j]=inf;
 6   for(int i=1;i<=n;i++)
 7   {
 8    for(int j=1;j<=6;j++)
 9      scanf("%d",wz[i]+j);
10    for(int j=1;j<=5;j+=2)
11    {
12     wz[i][7]+=wz[i][j];
13     wz[i][8]+=wz[i][j+1];
14    }
15  scanf("%d",wz[i]+9);

这里用了一个wz[][]数组,wz[i][j](j=1,3,5,7)表示第i座城市的四个点的横坐标,wz[i][j](j=2,4,6,8)表示第i座城市的四个点的纵坐标,而j=9则是路费。其中wz[i][7]与wz[i][8]是要去计算的。

而怎么算呢?我们可以得到一个公式xd=xa+xb-xc。 (y类似)(我们可以知道,已知的三点肯定是一个直角三角形,而(xa,ya)是TA的直角顶点,(xd,yd)便是TA所对的点。公式证明留给读者去思考。提示:利用两对角线交点是中点,然后使用中点坐标公式。)但我们还需要知道谁是直角顶点,这里很明显可以利用勾股定理求解。(当然还可以使用斜率乘积等于-1,但作者血与泪的教训还是建议你不要尝试。也可能是我太菜了
计算代码
 1 double tp[3];
 2 int tp2=inf,tp3;
 3 tp[0]=dist1(wz[i][4],wz[i][6],wz[i][3],wz[i][5]);
 4 tp[1]=dist1(wz[i][2],wz[i][6],wz[i][1],wz[i][5]);
 5 tp[2]=dist1(wz[i][2],wz[i][4],wz[i][1],wz[i][3]);
 6 if(tp[0]+tp[1]==tp[2]){//我在之前把wz[i][7]处理成wz[i][1,3,5]的和,
 7 //这里直接减两倍横纵坐标
 8  wz[i][7]-=2*wz[i][5];wz[i][8]-=2*wz[i][6];
 9 }
10 else if(tp[1]+tp[2]==tp[0]){
11  wz[i][7]-=2*wz[i][1];wz[i][8]-=2*wz[i][2];
12 }
13 else if(tp[0]+tp[2]==tp[1]){
14  wz[i][7]-=2*wz[i][3];wz[i][8]-=2*wz[i][4];
15 }
16 }

这是dis1函数

double dist(int a,int b,int c,int d){
 return sqrt((a-b)*(a-b)*1.0+1.0*(c-d)*(c-d));
}

然后枚举构造某城市之间飞机场的边。(这里我把城市里的每个顶点当一个点)

 1 for(int i=1;i<=n;i++)
 2 {
 3  for(int j=1;j<=4;j++)
 4    for(int k=j;k<=4;k++)
 5   {
 6    int u=(i-1)*4+j,v=(i-1)*4+k;//记得减一
 7    double dis=dist(wz[i][j*2-1],wz[i][k*2-1],wz[i][j*2],wz[i][k*2]);
 8    e[u][v]=e[v][u]=dis*wz[i][9];
 9   }
10 }

dist函数(与dist1的唯一区别就是开了根号)

1 double dist(int a,int b,int c,int d){
2  return sqrt((a-b)*(a-b)*1.0+1.0*(c-d)*(c-d));
3 }

接下来便是城市间最短距离的代码

 1 for(int i=1;i<=n;i++)
 2   for(int j=1;j<=n;j++)
 3     if(i!=j){//关键!!!作者调了一小时(┬_┬)
 4    for(int k=1;k<=4;k++)
 5      for(int l=1;l<=4;l++)
 6        {
 7         int u=(i-1)*4+k,v=(j-1)*4+l;
 8    double dis=dist(wz[i][k*2-1],wz[j][l*2-1],wz[i][k*2],wz[j][l*2]);
 9    e[u][v]=dis*tf;
10     }
11   }

然后便是我们期待已久的Floyd

for(int k=1;k<=n*4;k++)
  for(int i=1;i<=n*k;i++)
    for(int j=1;j<=n*4;j++)
      if(e[i][j]>e[i][k]+e[k][j])
          e[i][j]=e[i][k]+e[k][j];

最后枚举起点终点,找到最短路

1 ouble ans=inf;
2   for(int i=(a-1)*4+1;i<=a*4;i++)
3     for(int j=(b-1)*4+1;j<=b*4;j++)
4       ans=min(ans,e[i][j]);
5   printf("%.1lf",ans);

是不是很简单?

害我调了半天,万恶的Car
最后给出完整代码
 
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=100005,maxm=500005,inf=0x3f3f3f3f;
 4 double e[1005][1005];
 5 int wz[1005][11];
 6 int n,tf;
 7 double dist(int a,int b,int c,int d){
 8  return sqrt((a-b)*(a-b)*1.0+1.0*(c-d)*(c-d));
 9 }
10 double dist1(int a,int b,int c,int d){
11  return (a-b)*(a-b)*1.0+1.0*(c-d)*(c-d);
12 }
13 int main()
14 {
15  int t;
16  cin>>t;
17  while(t--)
18  {
19   int a,b;
20   scanf("%d%d%d%d",&n,&tf,&a,&b);
21   for(int i=1;i<=4*n;i++)
22     for(int j=1;j<=4*n;j++)
23       e[i][j]=inf;
24   for(int i=1;i<=n;i++)
25   {
26    for(int j=1;j<=6;j++)
27      scanf("%d",wz[i]+j);
28    for(int j=1;j<=5;j+=2)
29    {
30     wz[i][7]+=wz[i][j];
31     wz[i][8]+=wz[i][j+1];
32    }
33    scanf("%d",wz[i]+9);
34    double tp[3];
35    int tp2=inf,tp3;
36    tp[0]=dist1(wz[i][4],wz[i][6],wz[i][3],wz[i][5]);
37    tp[1]=dist1(wz[i][2],wz[i][6],wz[i][1],wz[i][5]);
38    tp[2]=dist1(wz[i][2],wz[i][4],wz[i][1],wz[i][3]);
39    if(tp[0]+tp[1]==tp[2]){
40     wz[i][7]-=2*wz[i][5];wz[i][8]-=2*wz[i][6];
41    }
42    else if(tp[1]+tp[2]==tp[0]){
43     wz[i][7]-=2*wz[i][1];wz[i][8]-=2*wz[i][2];
44    }
45    else if(tp[0]+tp[2]==tp[1]){
46     wz[i][7]-=2*wz[i][3];wz[i][8]-=2*wz[i][4];
47    }
48   }
49   for(int i=1;i<=n;i++)
50   {
51    for(int j=1;j<=4;j++)
52      for(int k=j;k<=4;k++)
53     {
54      int u=(i-1)*4+j,v=(i-1)*4+k;
55      double dis=dist(wz[i][j*2-1],wz[i][k*2-1],wz[i][j*2],wz[i][k*2]);
56      e[u][v]=e[v][u]=dis*wz[i][9];
57     }
58   }
59   for(int i=1;i<=n;i++)
60     for(int j=1;j<=n;j++)
61       if(i!=j){
62      for(int k=1;k<=4;k++)
63        for(int l=1;l<=4;l++)
64          {
65           int u=(i-1)*4+k,v=(j-1)*4+l;
66      double dis=dist(wz[i][k*2-1],wz[j][l*2-1],wz[i][k*2],wz[j][l*2]);
67      e[u][v]=dis*tf;
68       }
69     }
70   for(int k=1;k<=n*4;k++)
71     for(int i=1;i<=n*k;i++)
72       for(int j=1;j<=n*4;j++)
73         if(e[i][j]>e[i][k]+e[k][j])
74             e[i][j]=e[i][k]+e[k][j];
75   double ans=inf;
76   for(int i=(a-1)*4+1;i<=a*4;i++)
77     for(int j=(b-1)*4+1;j<=b*4;j++)
78       ans=min(ans,e[i][j]);
79   printf("%.1lf",ans);
80  }
81  return 0;
82 }

 

posted @ 2020-03-05 17:01  试试事实上吗  阅读(222)  评论(0编辑  收藏  举报
Live2D