首页 > 代码库 > FZU 2203 单纵大法好 (二分 && 贪心)
FZU 2203 单纵大法好 (二分 && 贪心)
题意 : 老S最近喜欢上某个搜集战舰的游戏,这个游戏中很重要的一个内容是能编排自己的战舰,通过出击完成任务来获取资源或新的战舰。大家都说老S是一个“直男”,所以他喜欢把战舰排成一条直线。目前老S正准备完成某个新的任务--“困难级丹麦海峡”,可以将地图视为1*N的一列方格(下标为1,2,...,N),老S有K列战舰,每列战舰长度为A。老S可以将自己的战舰布局在地图中的任意位置,但是两列战舰之间至少要有一个空格子,并且显然战舰是不能重叠放置的。老S通过内部人员率先知道了敌军的炮弹将会打向那些位置,老S希望使自己的舰队尽量晚的被第一次击中。请输出老S的舰队最晚将被敌方炮弹第一次击中?如果老S的舰队可以不被敌方炮弹击中则输出-1。
分析 : 由于要求求出第一次击中船只的炸弹可以多晚投放, 可以考虑在1~N这个区间内一个个炸弹地增加去尝试是否能够避免被击中, 直到出现无法避免被击中的情况, 那此时答案就是这个炸弹了, 若直到N也就是炸弹全投放都能避免被击中, 那就输出-1。但是这样的话时间是线性的, 如果单看炸弹的轰炸顺序, 从第一个炸弹开始, 随着炸弹数的增加, 区间内被轰击的点越多, 也就是轰炸到的船的可能性越大, 这是单调的, 所以可以考虑二分来挑选炸弹。其中判定能否被击中可以采用贪心策略, 炸弹击中的点将区间划分为几个, 此时只要考虑这几个区间能够容纳下几只船, 如果都能容纳, 说明在不能击中船只, 继续二分增大炸弹数, 当然了, 这里轰炸点是需要排序的。
瞎搞 : 听说这种贪心+二分是一类题型, 自己完全没有想到一个个炸弹地增加这样去思考, 完全就是在乱想, 还是弱啊........
#include<iostream> #include<stdio.h> #include<string.h> #include<string> #include<algorithm> using namespace std; const int maxn = 210000; int temp[maxn], bomb[maxn]; int N, K, len, ans = 0; bool Check(int x) { for(int i=1; i<=x; i++){ temp[i] = bomb[i]; } sort(temp+1, temp+1+x);//排序轰炸点, 方便贪心求出安全区间 temp[0] = 0; temp[x+1] = N+1; int cnt = 0; for(int i=0; i<=x; i++){ cnt += (temp[i+1] - temp[i])/(len+1);//这里算可容纳区间的方法巧妙, 可以借鉴 } if(cnt>=K) return true; else return false; } int main(void) { while(~scanf("%d %d %d", &N, &K, &len)){ int M; scanf("%d", &M); for(int i=1; i<=M; i++){ scanf("%d", &bomb[i]); } if(Check(M)){//如果M个炸弹一起上都能避免被轰击 puts("-1"); continue; } int L = 1, R = M, mid; while(L <= R){//二分炸弹数 mid = (R + L)>>1; if(Check(mid)) ans = mid, L = mid + 1; else R = mid - 1; } printf("%d\n", ans+1); } return 0; }
FZU 2203 单纵大法好 (二分 && 贪心)