The main walking trail in Geraldion is absolutely straight, and it passes strictly from the north to the south, it is so long that no one has ever reached its ends in either of the two directions. The Geraldionians love to walk on this path at any time, so the mayor of the city asked the Herald to illuminate this path with a few spotlights. The spotlights have already been delivered to certain places and Gerald will not be able to move them. Each spotlight illuminates a specific segment of the path of the given length, one end of the segment is the location of the spotlight, and it can be directed so that it covers the segment to the south or to the north of spotlight.
The trail contains a monument to the mayor of the island, and although you can walk in either directions from the monument, no spotlight is south of the monument.
You are given the positions of the spotlights and their power. Help Gerald direct all the spotlights so that the total length of the illuminated part of the path is as much as possible.
The first line contains integer n (1 ≤ n ≤ 100) — the number of spotlights. Each of the n lines contains two space-separated integers, aiand li (0 ≤ ai ≤ 108, 1 ≤ li ≤ 108). Number ai shows how much further the i-th spotlight to the north, and number li shows the length of the segment it illuminates.
It is guaranteed that all the ai's are distinct.
Print a single integer — the maximum total length of the illuminated part of the path.
3 1 1 2 2 3 3
5
4 1 2 3 3 4 3 6 2
9
题意给出的是,一条路上有几个不相同的灯,灯可以向左也可以向右照亮一定的距离,要求,所有的灯可以照亮的最大距离。
一开始的想法,肯定是每个灯向左也向右试下,看看最大值就可以了。当然这样,是指数级复杂度的,所以不可取。其中肯定有大量的重复不必要的状态,所以可以按照dp的思想,定义dfs[sv,si]从值sv开始,从下标si开始,所能取到的最大值。则转状转移可以分为以下情况。
这里u是照亮区域的最大值,mj是灯位置大于u且在照亮范围内的最大的下标
1.如果,第si - n个灯向左照亮,则位置小于相应的u的灯一定是向右照亮的,因为,如果它向左,照亮的区域大于亮的区域左端点,没有意义,而小于亮的端点,又是这里讨论的si - n中的一个值,也没有意义。而其位置大于照亮区域的灯,则是其状态转移的一个子问题 ,也就是代码中DFS(u,mj+1);这里转移到了以u开始,以mj+1开始的最大值的子问题。如图
2.如果第si个灯向右照亮,则任何大于si且其位置小于照亮区域的灯一定是向右的(因为如果向左,则是第一种情况讨论的情况,也就是一个向左,小于他的向右照亮)。而其位置大于照亮区域的灯,则是其状态转移的一个子问题 ,也就是代码中DFS(u,mj+1);这里转移到了以u开始,以mj+1开始的最大值的子问题。
这样,所以的问题都可以转化成一个小的子问题 ,大家当然知道,用记忆化搜索是最简单的,由于这里的u是很大的值,所以直接用map存取,是很方便的。
这里说下时间复杂度,总的状态数有2 * n * n种,状态转移有n * n 种,一次查询要log(2*n),所以总的复杂度达到了o(n ^ 4 * log(n)).但是这里是记忆化搜索,省去子大量的重复子状态,所以,总的复杂度,其实没有那么高,能很快搜索出来答案。
#define N 105
#define M 100005
#define maxn 205
#define MOD 1000000007
int n;
pii p[N];
map<pii,int> mymap;
int DFS(int sv,int si){
if(si >= n ) return 0;
if(mymap.count(mp(sv,si))) return mymap[mp(sv,si)];
int maxx = 0,t,mj,u;
for(int i = si;i<n;i++){
mj = i;u = p[i].first;t = p[i].first - max(sv,p[i].first - p[i].second);
for(int j = si;j<n&& p[j].first <= u;j++)
if(i != j){
mj = max(mj,j);
if(p[j].first + p[j].second > u){
t+= p[j].first + p[j].second - u;
u = p[j].first + p[j].second ;
}
}
t+= DFS(u,mj+1);
maxx = max(maxx,t);
}
mj = si,u = p[si].first + p[si].second;t = p[si].second;
for(int i = si + 1;i<n && p[i].first <= u;i++){
mj = i;
if(p[i].first + p[i].second > u){
t+= p[i].first + p[i].second - u;
u = p[i].first + p[i].second ;
}
}
t+= DFS(u,mj+1);
maxx = max(maxx,t);
return mymap[mp(sv,si)] = maxx;
}
int main()
{
while(S(n)!=EOF)
{
FI(n){
cin>>p[i].first>>p[i].second;
}
sort(p,p+n);
mymap.clear();
cout<<DFS(-MOD,0)<<endl;
}
return 0;
}