• 【noi 2.6_687】Color Tunnels(DP)


    P.S.o(︶︿︶)o 唉~虽然这题方程不难,但题目长,代码长,我花了超过3小时!(>﹏<)悲伤辣么大~~~ 谨此题解惠及众人,hh。

    题意:给定长度为M的一串颜色序列,和平面上的N个颜色隧道。要求以颜色序列的顺序通过颜色隧道。(隧道可多次使用,可交叉,互不相同。)问从源点到汇点依次通过颜色的最小距离。

    解法:f[i][j]表示通过颜色序列前 i 个颜色,这次的第 i 个颜色的隧道选 j 的最小距离。枚举第 i-1 个颜色选的隧道为 k ,则:f[i][j] = min( f[i][j] , f[i-1][k] + dis( a[k].xx , a[k].yy , a[j].x , a[j].y) + a[j].l );

    我是规定每个隧道从(x,y)到(xx,yy)通过,所以读入时存2*N个隧道,(x,y)和(xx,yy)调换。这样就可以减去大部分人分f[i][j][0] 和 f[i][j][1]的多情况分析讨论,具体优越处见代码。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 #include<cmath>
     7 using namespace std;
     8 #define M 35
     9 #define N 65
    10 #define C 105
    11 #define INF 2e9
    12 
    13 int m,n;
    14 double xs,ys,xt,yt;
    15 int q[M];
    16 struct node{double x,y,xx,yy,l;int c;};
    17 node a[2*N];
    18 double f[2][2*N];
    19 
    20 void ins(int id,double x,double y,double xx,double yy,int c)
    21 {
    22     a[id].x=x,a[id].y=y,a[id].c=c;
    23     a[id].xx=xx,a[id].yy=yy;
    24     a[id].l=sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy));
    25 }
    26 double mmin(double x,double y) {return x<y?x:y;}
    27 double dis(double x,double y,double xx,double yy) {return sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy));}
    28 
    29 int main()
    30 {
    31     int T,i,j,k;
    32     scanf("%d",&T);
    33     while (T--)
    34     {
    35       scanf("%lf%lf%lf%lf",&xs,&ys,&xt,&yt);
    36       scanf("%d",&m);
    37       for (i=1;i<=m;i++) scanf("%d",&q[i]);
    38       scanf("%d",&n);
    39       for (i=1;i<=n;i++)
    40       {
    41         double x,y,xx,yy;int c;
    42         scanf("%lf%lf%lf%lf%d",&x,&y,&xx,&yy,&c);
    43         ins(2*i-1,x,y,xx,yy,c),ins(2*i,xx,yy,x,y,c);
    44       }
    45       n*=2;
    46       
    47       double ans=INF;
    48       for (j=1;j<=n;j++)
    49       {
    50         if (a[j].c!=q[1]) continue;
    51         f[1][j]=dis(xs,ys,a[j].x,a[j].y)+a[j].l;
    52         if (m==1) ans=mmin(ans,f[1][j]+dis(a[j].xx,a[j].yy,xt,yt));//xx,yy
    53       }
    54       int u=1;
    55       for (i=2;i<=m;i++)
    56       {
    57         u=1-u;
    58         for (j=1;j<=n;j++)
    59         {
    60           f[u][j]=INF;
    61           if (a[j].c!=q[i]) continue;
    62           for (k=1;k<=n;k++)
    63           {
    64             if (a[k].c!=q[i-1]) continue;
    65             f[u][j]=mmin(f[u][j],f[1-u][k]+dis(a[k].xx,a[k].yy,a[j].x,a[j].y)+a[j].l);
    66           }
    67           if (i==m) ans=mmin(ans,f[u][j]+dis(a[j].xx,a[j].yy,xt,yt));//xx,yy
    68         }
    69       }
    70       printf("%.4lf
    ",ans);
    71     }
    72     return 0;
    73 }
    View Code 我的方法+滚动数组
     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<cmath>
     6 using namespace std;
     7 
     8 const int N=110,M=110;
     9 const double INF=(double)1e9;
    10 int n,m;
    11 int c[N];
    12 double d[N][M][2];
    13 struct node{double x,y;};
    14 struct edge{node s,d;double len;int c;}a[N];
    15 double minn(double x,double y){return x<y ? x:y;}
    16 double dist(node t1,node t2){
    17     return sqrt((t1.x-t2.x)*(t1.x-t2.x)+(t1.y-t2.y)*(t1.y-t2.y));
    18 }
    19 
    20 int main()
    21 {
    22     int T;
    23     scanf("%d",&T);
    24     while(T--)
    25     {
    26         node st,ed;
    27         scanf("%lf%lf%lf%lf",&st.x,&st.y,&ed.x,&ed.y);
    28         scanf("%d",&n);
    29         for(int i=1;i<=n;i++)
    30             scanf("%d",&c[i]);
    31         scanf("%d",&m);
    32         for(int i=1;i<=m;i++)
    33         {
    34             scanf("%lf%lf%lf%lf%d",&a[i].s.x,&a[i].s.y,&a[i].d.x,&a[i].d.y,&a[i].c);
    35             a[i].len=dist(a[i].s,a[i].d);
    36         }
    37         double mn=INF;
    38         for(int i=1;i<=m;i++)
    39         {
    40             if(a[i].c==c[1]) 
    41             {
    42                 d[1][i][0]=dist(st,a[i].s)+a[i].len;
    43                 d[1][i][1]=dist(st,a[i].d)+a[i].len;    
    44                 if(n==1) mn=minn(mn,minn(d[1][i][0]+dist(a[i].d,ed),d[1][i][1]+dist(a[i].s,ed)));
    45             }
    46         }
    47         for(int i=2;i<=n;i++)
    48         {
    49             for(int j=1;j<=m;j++)
    50             {    
    51                 d[i][j][0]=d[i][j][1]=INF;
    52                 if(a[j].c!=c[i]) continue;
    53                 for(int k=1;k<=m;k++)
    54                 {
    55                     if(a[k].c!=c[i-1]) continue;
    56                     d[i][j][0]=minn(d[i][j][0],a[j].len+minn(d[i-1][k][0]+dist(a[k].d,a[j].s),d[i-1][k][1]+dist(a[k].s,a[j].s)));
    57                     d[i][j][1]=minn(d[i][j][1],a[j].len+minn(d[i-1][k][0]+dist(a[k].d,a[j].d),d[i-1][k][1]+dist(a[k].s,a[j].d)));
    58                     // printf("%d  %d  d1 = %.3lf  d2 = %.3lf
    ",i,j,d[i][j][0],d[i][j][1]);
    59                 }
    60                 if(i==n) mn=minn(mn,minn(d[i][j][0],d[i][j][1]));//dist(a[j].d,ed)dist(a[j].s,ed)
    61             }
    62         }
    63         printf("%.4lf
    ",mn);
    64     }
    65     return 0;
    66 }
    View Code 他人的方法(from gyw)

    P.S.而且我他人的方法我选的还是很简短的代码,我看oj上大部分人都是2千多Byte的。这2个代码是1千5、6百多Byte。

    而我还打了另外一个PG,将颜色隧道按颜色排序了,j和k的循环量比原来的2*N减少了,但是由于排序是O(n log n),N的数据范围也只是几十,所以这个反而速度慢一点。另外。。这个程序只拿了5分,我不知道为何WA,求助啊!●o●

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 #include<cmath>
     7 using namespace std;
     8 #define M 35
     9 #define N 65
    10 #define C 105
    11 #define INF 2e9
    12 
    13 int m,n;
    14 double xs,ys,xt,yt;
    15 int q[M],s[C];
    16 struct node{double x,y,xx,yy,l;int c;};
    17 node a[2*N];
    18 double f[2][2*N];
    19 
    20 void ins(int id,double x,double y,double xx,double yy,int c)
    21 {
    22     a[id].x=x,a[id].y=y,a[id].c=c;
    23     a[id].xx=xx,a[id].yy=yy;
    24     a[id].l=sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy));
    25 }
    26 bool cmp(node x,node y) {return x.c<y.c;}
    27 double mmin(double x,double y) {return x<y?x:y;}
    28 double dis(double x,double y,double xx,double yy) {return sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy));}
    29 
    30 int main()
    31 {
    32     int T,i,j,k;
    33     scanf("%d",&T);
    34     while (T--)
    35     {
    36       scanf("%lf%lf%lf%lf",&xs,&ys,&xt,&yt);
    37       scanf("%d",&m);
    38       for (i=1;i<=m;i++) scanf("%d",&q[i]);
    39       scanf("%d",&n);
    40       for (i=1;i<=n;i++)
    41       {
    42         double x,y,xx,yy;int c;
    43         scanf("%lf%lf%lf%lf%d",&x,&y,&xx,&yy,&c);
    44         ins(2*i-1,x,y,xx,yy,c),ins(2*i,xx,yy,x,y,c);
    45       }
    46       n*=2;
    47       sort(a+1,a+1+n,cmp);
    48       
    49       int c,cc;
    50       c=s[0]=a[0].c=0;
    51       for (i=1;i<=n;i++)
    52        if (a[i].c!=a[i-1].c)
    53        {
    54          while (c<a[i].c) s[++c]=i-1;
    55          s[a[i].c]=i;
    56        }
    57       s[a[n].c+1]=n+1;
    58         
    59       double ans=INF;
    60       q[0]=0,q[m+1]=a[n].c+1;
    61       ins(0,xs,ys,xs,ys,0),ins(n+1,xt,yt,xt,yt,a[n].c+1);
    62       s[a[n].c+2]=n+2;
    63       f[0][0]=0.0;
    64       
    65       int u=1;
    66       for (i=1;i<=m+1;i++)
    67       {
    68         c=q[i],cc=q[i-1];
    69         for (j=s[c];j<s[c+1];j++)
    70         {
    71          f[u][j]=INF;
    72          for (k=s[cc];k<s[cc+1];k++)
    73            f[u][j]=mmin(f[u][j],f[1-u][k]+dis(a[k].xx,a[k].yy,a[j].x,a[j].y)+a[j].l);
    74          if (i==m+1) ans=mmin(ans,f[u][j]);
    75         }
    76         u=1-u;
    77       }
    78       printf("%.4lf
    ",ans);
    79     }
    80     return 0;
    81 }
    View Code 排序+滚动数组(WA)
  • 相关阅读:
    每日日报2020.9.30 1905
    每日日报2020.10.7 1905
    每日日报2020.10.2 1905
    每日日报2020.9.28 1905
    程序员修炼之道:从小工到专家 九月读书心得 1905
    每日日报2020.9.27 1905
    每日日报2020.9.29 1905
    每日日报2020.10.6 1905
    每日日报2020.10.5 1905
    每日总结2
  • 原文地址:https://www.cnblogs.com/konjak/p/6006933.html
Copyright © 2020-2023  润新知