hdu 3698 Let the light guide us(线段树优化&简单DP)
Let the light guide us
Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 62768/32768 K (Java/Others)
Total Submission(s): 677 Accepted Submission(s): 226
Recently an accident destroyed the eternal tranquility. Some greedy fools tried using powerful bombs to find the hidden treasure. Of course they failed and such behavior enraged those spirits--the consequence is that all the human villages nearby are haunted by ghosts.
In order to stop those ghosts as soon as possible, Panda the Archmage and Facer the great architect figure out a nice plan. Since the plain can be represented as grids of N rows and M columns, the plan is that we choose ONLY ONE cell in EACH ROW to build a magic tower so that each tower can use holy light to protect the entire ROW, and finally the whole plain can be covered and all spirits can rest in peace again. It will cost different time to build up a magic tower in different cells. The target is to minimize the total time of building all N towers, one in each row.
“Ah, we might have some difficulties.” said Panda, “In order to control the towers correctly, we must guarantee that every two towers in two consecutive rows share a common magic area.”
“What?”
“Specifically, if we build a tower in cell (i,j) and another tower in cell (i+1,k), then we shall have |j-k|≤f(i,j)+f(i+1,k). Here, f(i,j) means the scale of magic flow in cell (i,j).”
“How?”
“Ur, I forgot that you cannot sense the magic power. Here is a map which shows the scale of magic flows in each cell. And remember that the constraint holds for every two consecutive rows.”
“Understood.”
“Excellent! Let’s get started!”
Would you mind helping them?
Each test case starts with a line containing 2 integers N and M (2<=N<=100,1<=M<=5000), representing that the plain consists N rows and M columns.
The following N lines contain M integers each, forming a matrix T of N×M. The j-th element in row i (Tij) represents the time cost of building a magic tower in cell (i, j). (0<=Tij<=100000)
The following N lines contain M integers each, forming a matrix F of N×M. The j-th element in row i (Fij) represents the scale of magic flows in cell (i, j). (0<=Fij<=100000)
For each test case, there is always a solution satisfying the constraints.
The input ends with a test case of N=0 and M=0.
9 5 3 8 7
8 2 6 8 9
1 9 7 8 6
0 1 0 1 2
1 0 2 1 1
0 2 1 0 2
0 0
题意:
要在N*M(n<=100.m<=5000)的矩形区域的每行的一个位置建灯塔。而在第i行的j列建塔要花费时间ti[i][j].建塔还必须满足一个条件。
如果本行在j列建塔。下行在k列建塔。那么必须满足|j-k|<=f[i][j]+f[i+1][k]。
f[i][j]由题目给出。
问每行建完塔花费的最小时间。
思路:
很容易想到一个动规方程。dp[i][j]=min(dp[i][j],dp[i-1][k]+ti[i][j])。dp[i][j]代表前面i-1行建好塔。第i行在j列建塔的最小花费。
可问题又来了。这个k怎么确定。。。。。
如果暴力枚举的话时间复杂度为O(n*m*m)。目测最好n,m取最大的时候大于9秒吧。这还是单组数据。。。
所以不得不找其它办法优化下。
这个估计就要点思维了。我也是看了别人的转化才恍然大悟的。
我们去掉绝对值可以得到两个方程。
j-f[i][j]<=k+f[i+1][k]。 j>=k。
k-f[i+1][k]<=j+f[i][j]。 j<k。
可以发现k的取值范围即为区间[j-f[i][j],j+f[i][j]]和[k-f[i+1][k],k+f[i+1][k]]相交的部分。
所以思路就清晰了。要求dp[i][j]只需要知道上一行和[j-f[i][j],j+f[i][j]]相交部分的最小值就可以了。
而这个值可以用线段树维护。时间复杂度降到了。O(n*m*log(m))这下就没问题了。
详细见代码:
- #include<algorithm>
- #include<iostream>
- #include<sstream>
- #include<string.h>
- #include<stdio.h>
- #include<math.h>
- #include<vector>
- #include<string>
- #include<queue>
- #include<map>
- using namespace std;
- const int INF=0x3f3f3f3f;
- const int maxn=150;
- const int maxm=5010;
- int ti[maxn][maxm],f[maxn][maxm],minv[maxm<<2],lazy[maxm<<2];
- int dp[maxm],n,m;
- void btree(int L,int R,int k)
- {
- int ls,rs,mid;
- minv[k]=lazy[k]=INF;
- if(L==R)
- return ;
- ls=k<<1;
- rs=ls|1;
- mid=(L+R)>>1;
- btree(L,mid,ls);
- btree(mid+1,R,rs);
- }
- void pushdown(int k,int ls,int rs)
- {
- minv[ls]=min(minv[ls],lazy[k]);
- minv[rs]=min(minv[rs],lazy[k]);
- lazy[ls]=min(lazy[ls],lazy[k]);
- lazy[rs]=min(lazy[rs],lazy[k]);
- lazy[k]=INF;
- }
- void update(int L,int R,int l,int r,int k,int v)
- {
- int ls,rs,mid;
- if(L==l&&R==r)
- {
- minv[k]=min(minv[k],v);
- lazy[k]=min(lazy[k],v);
- return;
- }
- ls=k<<1;
- rs=ls|1;
- mid=(L+R)>>1;
- if(lazy[k]!=INF)
- pushdown(k,ls,rs);
- if(l>mid)
- update(mid+1,R,l,r,rs,v);
- else if(r<=mid)
- update(L,mid,l,r,ls,v);
- else
- {
- update(L,mid,l,mid,ls,v);
- update(mid+1,R,mid+1,r,rs,v);
- }
- minv[k]=min(minv[ls],minv[rs]);
- }
- int qu(int L,int R,int l,int r,int k)
- {
- int ls,rs,mid;
- if(L==l&&R==r)
- return minv[k];
- ls=k<<1;
- rs=ls|1;
- mid=(L+R)>>1;
- if(lazy[k]!=INF)
- pushdown(k,ls,rs);
- if(l>mid)
- return qu(mid+1,R,l,r,rs);
- else if(r<=mid)
- return qu(L,mid,l,r,ls);
- else
- return min(qu(L,mid,l,mid,ls),qu(mid+1,R,mid+1,r,rs));
- }
- int main()
- {
- int i,j,l,r,ans;
- while(scanf("%d%d",&n,&m),n||m)
- {
- for(i=1;i<=n;i++)
- for(j=1;j<=m;j++)
- scanf("%d",&ti[i][j]);
- for(i=1;i<=n;i++)
- for(j=1;j<=m;j++)
- scanf("%d",&f[i][j]);
- for(i=1;i<=m;i++)
- dp[i]=ti[1][i];
- for(i=2;i<=n;i++)
- {
- btree(1,m,1);
- for(j=1;j<=m;j++)
- {
- l=max(j-f[i-1][j],1);
- r=min(j+f[i-1][j],m);
- update(1,m,l,r,1,dp[j]);
- }
- for(j=1;j<=m;j++)
- {
- l=max(j-f[i][j],1);
- r=min(j+f[i][j],m);
- dp[j]=qu(1,m,l,r,1)+ti[i][j];
- }
- }
- ans=INF;
- for(i=1;i<=m;i++)
- ans=min(ans,dp[i]);
- printf("%d\n",ans);
- }
- return 0;
- }
hdu 3698 Let the light guide us(线段树优化&简单DP)的更多相关文章
- hdu 3698 UVA1490 Let the light guide us 线段树优化DP
题目链接 and 题目大意 hdu3698 但是 hdu的数据比较弱,所以在这luogu提交吧UVA1490 Let the light guide us 有一个\(n*m\)的平原,要求每行选一个点 ...
- 题解 HDU 3698 Let the light guide us Dp + 线段树优化
http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java ...
- HDU 3698 Let the light guide us(DP+线段树)(2010 Asia Fuzhou Regional Contest)
Description Plain of despair was once an ancient battlefield where those brave spirits had rested in ...
- HDU 3698 Let the light guide us
Let the light guide us Time Limit: 2000ms Memory Limit: 32768KB This problem will be judged on HDU. ...
- BZOJ 3790 神奇项链(回文自动机+线段树优化DP)
我们预处理出来以i为结尾的最长回文后缀(回文自动机的构建过程中就可以求出)然后就是一个区间覆盖,因为我懒得写贪心,就写了线段树优化的DP. #include<iostream> #incl ...
- hdu3698 Let the light guide us dp+线段树优化
http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java ...
- hdu 4117 GRE Words (ac自动机 线段树 dp)
参考:http://blog.csdn.net/no__stop/article/details/12287843 此题利用了ac自动机fail树的性质,fail指针建立为树,表示父节点是孩子节点的后 ...
- HDU多校第三场 Hdu6606 Distribution of books 线段树优化DP
Hdu6606 Distribution of books 题意 把一段连续的数字分成k段,不能有空段且段和段之间不能有间隔,但是可以舍去一部分后缀数字,求\(min(max((\sum ai ))\ ...
- Weak Pair---hud5877大连网选(线段树优化+dfs)
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5877 题意:给你一颗树,有n个节点,每个节点都有一个权值v[i]:现在求有多少对(u,v ...
随机推荐
- for循环,如何结束多层for循环
采用标签方式跳出,指定跳出位置, a:for(int i=0;i<n;i++) { b:for(int j=0;j<n;j++) { if(n=0) { break a; } } }
- webServices 执行流程,(我是菜鸟,我怕谁,仅代表个人理解,欢迎各位大神们指导,不和您的胃口,请默默离开!!)
二.上图仅仅代表个人理解,下面以代码方式解释一下. (1) strtus.xml <?xml version="1.0" encoding="UTF-8" ...
- linux常用命令之ln
ln是linux中又一个非常重要命令,它的功能是为某一个文件在另外一个位置建立一个同不的链接,这个命令最常用的参数是-s,具体用法是:ln –s 源文件 目标文件. 当我们需要在不同的目录,用到相同的 ...
- 对 const char* const &a 的理解
定义中用到&是独立引用. 比如: char i; char &a=i; 表示a是i的一个单独引用. 当有i='a'时,也有a='a'; 当有a='c'时,也有i='c'; 两个变量的标 ...
- 图的遍历(bfs 和dfs)
BFS的思想: 从一个图的某一个顶点V0出发,首先访问和V0相邻的且未被访问过的顶点V1.V2.……Vn,然后依次访问与V1.V2……Vn相邻且未被访问的顶点.如此继续,找到所要找的顶点或者遍历完整个 ...
- 封装Timer
System.Timers.Timer,System.Timers.Timer在使用的过程中需要: 1.构造函数不同,构造函数可以什么事情也不做,也可以传入响应间隔时间:System.Timers.T ...
- ExtJs 第二章,Ext.form.Basic表单操作
1.认识Ext.form.Panel表单面板 Ext.form.field.CheckBox 复选框 checkboxfield Ext.form.CheckBoxGroup 复选框组 ...
- oc 怎么接收NSSting字符的方法
]; //使用一个缓冲区 NSLog(@"请输入一个字符串:"); scanf("%s",buffer); NSString * str = [NSString ...
- mysql更新密码为空
1.进入命令行 mysql -u root -p 'oldpassword'; 2 修改root用户的密码:mysql> update mysql.user set password=PASSW ...
- jQuery之文本框得失焦点
版本一 css代码部分: .focus { border: 1px solid #f00; background: #fcc; } 当焦点获得时,添加focus样式,添加边框,并改背景色为#fcc h ...