1475 建设国家
基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题
小C现在想建设一个国家。这个国家中有一个首都,然后有若干个中间站,还有若干个城市。
现在小C想把国家建造成这样的形状:选若干(可以是0个)的中间站把他们连成一条直线,然后把首都(首都也是一个中间站)连在这一条直线的左端。然后每个点可以连一个城市,特别的是最右端的点可以连接两个城市。
现在有n个城市的规划供小C选择。但是,他们那儿的交通条件比较差,他们那儿一天是2*H个小时,每个城市里面的人每天都会去首都拿一样东西,从他们所在的城市出发,到了首都之后拿了东西就走(拿东西的时间可以忽略不计),他们要在2*H个小时之内返回他们自己的家中(从家中出发到返回家中不超过2*H小时)。
每个城市有两个属性,一个是城市的直径,另外一个是能居住的人口数目。对于第i个城市而言,这两个属性分别是hi,pi。
城市的直径的意思是离这个城市出口最远的人想要出城先要在城里行走的最少的时间。
在首都,中间站,城市之间行走要花费1小时的时间。
小C想选择一些城市然后通过若干的中间站和首都连接起来,在每个人能在2*H小时返回的条件下所有城市居住的总人口数目要最多。
样例解释:最上面的蓝点表示首都,其它的蓝点表示中间站,剩下的红圈表示选择的城市。
Input
单组测试数据。
第一行包含两个整数n 和H (1 ≤ n ≤ 1000,1 ≤ H ≤ 1000000000),表示可供选择的城市数目和时间限制。
接下来n行,每行有两个整数hi, pi (1 ≤ hi ≤ H, 1 ≤ pi ≤ 1000),第i个城市的两个属性,即直径和能容纳人口数。
Output
输出最多能居住的人口数目。
Input示例
5 10
1 1
1 1
2 2
3 3
4 4
Output示例
11
都说是优先队列….看来我的解法比较非主流
首先简化一下问题 假设最下方的中间站只能连接一个城市
又因为
第1个中间站连接的城市直径必须<=H-1
第2个中间站连接的城市直径必须<=H-2
……
第H-1个中间站连接的城市直径必须<=1
对这个问题 我们用贪心求解 对所有城市 按p降序排列 (p相同 按h降序)
依次遍历每个城市 c[i]
c[i]只能放在 H-k >= c[i].h 的位置
将c[i]放在 H-k 尽可能小的位置 显然是最优策略
看回原问题 其实就等价于
用上述贪心策略求解
第1个中间站连接的城市直径必须<=H-1
第2个中间站连接的城市直径必须<=H-2
……
第H-k个中间站连接的城市直径必须<=H-k
得res1
穷举c[i] 0 < i < n-1
以c[i].h作为k
res=res1+c[i].p
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string>
#include<vector>
#include<deque>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<time.h>
#include<math.h>
#include<list>
#include<cstring>
#include<fstream>
#include<bitset>
//#include<memory.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define INF 1000000007
#define pll pair<ll,ll>
#define pid pair<int,double>
set<int>used;//标记pos是否被用了
struct City{
int h,p;
}c[1005];
bool comp(const City&a,const City&b){
if(a.p==b.p)
return a.h>b.h;
return a.p>b.p;
}
int slove(int n,int H){
sort(c,c+n,comp);
int res=0;
--H;
for(int i=0;i<n;++i){//枚举最后一个中间站连接的城市
if(c[i].h>H)//没有中间站能连接c[i]
continue;
used.clear();
int size=0;
int sum=c[i].p;
for(int j=0;j<n;++j){//贪心求H-1 --- c[i].h位置的城市
if(i==j||c[j].h<c[i].h)
continue;
if(H-c[i].h+1==size)//全部中间站都填满了
break;
int pos=c[j].h;//连接的位置
while(pos<=H&&used.find(pos)!=used.cend())
++pos;
if(pos<=H){//连接上
++size;
used.insert(pos);
sum+=c[j].p;
}
}
res=max(res,sum);
}
return res;
}
int main()
{
//freopen("/home/lu/文档/r.txt","r",stdin);
//freopen("/home/lu/文档/w.txt","w",stdout);
int n,H;
scanf("%d%d",&n,&H);
for(int i=0;i<n;++i)
scanf("%d%d",&c[i].h,&c[i].p);
cout<<slove(n,H)<<endl;
return 0;
}