2019中山纪念中学夏令营-Day20[JZOJ] T1旅游详解

2019中山纪念中学夏令营-Day20[JZOJ]

提高组B组 Team_B组

T1 旅游 Time Limits: 2000 ms  Memory Limits: 262144 KB

Description
ztxz16如愿成为码农之后,整天的生活除了写程序还是写程序,十分苦逼。终于有一天,他意识到自己的生活太过平淡,于是决定外出旅游丰富阅历。

ztxz16生活的城市有N*M个景点,可以描述成一个N*M的矩形,每个景点有一个坐标(x, y) (1 <= x <= N, 1 <= y <= M)以及美观度A[x][y]和观赏所需的时间B[x][y],从一个景点(x1, y1)走到另一个景点(x2, y2)需要时间为它们之间的曼哈顿距离:|x1 - x2| +|y1 - y2|。

为了防止审美疲劳,ztxz16希望观赏的景点的的美观度是严格上升的,由于不想太早回家码代码,ztxz16希望旅游的总时间尽可能长。
 
Input
第一行输入两个整数N, M;

接下来N行每行M个整数,第x行第y个整数代表A[x][y];

接下来N行每行M个整数,第x行第y个整数代表B[x][y];

注意,有一些A[x][y]=B[x][y]=0,说明这个景点已经拆除,不能游览;
Output
输出一行代表最长的总时间。
 
Sample Input
4 5
1 2 6 0 2
1 3 4 0 4
0 0 4 0 3
2 2 0 0 4
1 3 5 0 2
2 8 1 0 2
0 0 3 0 4
0 5 0 0 3
Sample Output
39
【样例说明】
游览顺序为(2,1)->(1,5)->(2,2)->(4,5)->(1,3)
 
 
Data Constraint
对于30%的数据:1<=N<=50 , 1<=M<=50

对于60%的数据:1<=N<=300 , 1<=M<=300

对于100%的数据:1<=N<=1000 , 1<=M<=1000

 0<=A[x][y]<=1000000

 0<=B[x][y]<=10^9

注意:本题输入数据较大,请注意输入消耗的时间

 

官方正解:

用f[x][y]表示游览到(x,y)时可能的最长时间,将曼哈顿距离中的绝对值展开后,转移可以表示为四个子矩形中求max的问题,可以使用二维树状数组维护
继续观察发现因为题目要求总长度尽可能长,因此每个点只会在正确的子矩形中贡献最大的答案,因此不需要使用二维树状数组,只需按符号考虑四种情况即可

听说好像要用四边形不等式(反正我也不懂,就瞎搞吧

我的思路:

先用结构体存矩阵,使其压成一维,然后开始DP乱搞

我们显然可以发现,最优解一定是从上一个观赏度和当前观赏度之差绝对值最小的地方转换过来的

因此可以给DP剪掉一些不可能最优的转移,因为每个点i的bi(即观赏时间)是一定的,我们可以把它从转移式中提出来。

状态转移方程:

其中:k为上一阶段的观赏度的点排序后的编号(用来剪不必要的转移用的),如果不理解的话可以将j=0,但是会慢很多。

代码实现:

 1 #include <cstdio>
 2 #include <algorithm>
 3 #define rr register
 4 #define int long long
 5 using std::sort;
 6 int n,m,f[1005*1005],mark1,mark2,maxn,h[1005][1005];
 7 struct Node{
 8     int x,y,a,b;
 9 }node[1005*1005];
10 bool cmp(Node k,Node l)
11 {
12     return k.a<l.a;
13 }
14 int max(int k,int l)
15 {
16     if(k>l)
17         return k;
18     return l;
19 }
20 int abs(int k)
21 {
22     if(k<0)
23         return -k;
24     return k;
25 }
26 signed main()
27 {
28     scanf("%lld %lld",&n,&m);
29     int tot=1;
30     for(rr int i=1;i<=n;i++)
31         for(rr int j=1;j<=m;j++)
32         {
33             scanf("%lld",&h[i][j]);
34         }
35         tot=1;
36     for(rr int i=1;i<=n;i++)
37         for(rr int j=1;j<=m;j++)
38         {
39             int tmp;
40             scanf("%lld",&tmp);
41             if(tmp==0 && h[i][j]==0)
42                 continue;
43             node[tot].a=h[i][j];
44             node[tot].b=tmp;
45             node[tot].x=i;
46             node[tot].y=j;
47             tot++;
48         }
49         tot--;
50     sort(node+1,node+tot+1,cmp);
51     for(rr int i=1;i<=tot;i++)
52     {
53         if(node[i].a>node[i-1].a)
54             {
55                 mark2=mark1;
56                 mark1=i-1;
57             }    
58         if(node[i].a==0 && node[i].b==0)
59             continue;
60     
61         for(rr int j=max(mark2,1);j<i;j++)
62         {
63             if(node[i].a>node[j].a)
64             {
65                 if(f[i] < f[j]+abs(node[i].x-node[j].x)+abs(node[i].y-node[j].y))
66                     f[i] = f[j]+abs(node[i].x-node[j].x)+abs(node[i].y-node[j].y);
67             }
68         }
69         f[i]+=node[i].b;
70         maxn=max(maxn,f[i]);
71     }
72     
73     printf("%lld",maxn);
74 }

 

转载于:https://www.cnblogs.com/XYYXP/p/2019-8-20_JZOJ_TEAM-B_TIGAO_DAY20.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值