【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\n",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\n",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\n",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\n",ans);
79     }
80     return 0;
81 }
View Code 排序+滚动数组(WA)

 

转载于:https://www.cnblogs.com/konjak/p/6006933.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值