有N只兔子,每只有一个血量B[i],需要用箭杀死免子。有M种不同类型的箭可以选择,每种箭对兔子的伤害值分别为D[i],价格为P[i](1 <= i <= M)。假设每种箭只能使用一次,每只免子也只能被射一次,计算要消灭地图上的所有兔子最少需要多少Q币。如不能杀死所有兔子,请输出No Solution。
特别说明:1、当箭的伤害值大于等于兔子的血量时,能将兔子杀死;2、血量B[i],箭的伤害值D[i],箭的价格P[i],均小于等于100000。
Input
第1行:两个整数N,M,中间用空格分隔(1 <= N, M <= 50000),分别表示兔子的个数和箭的种类。
第2 - N + 1行:每行1个正整数(共N行),表示兔子的血量B[i](1 <= B[i] <= 100000)。
第N + 2 - N + M + 1行:每行2个正整数(共M行),中间用空格分隔,表示箭所能造成的伤害值D[i],和需要花费的Q币P[i](1 <= D[i], P[i] <= 100000)。
Output
输出最少需要多少Q币才能消灭所有的兔子。如果不能杀死所有兔子,请输出"No Solution"。
3 3 1 2 3 2 1 3 2 4 3
6这道题我一开始的思路是,将兔子血量从小到大排序,再将箭的伤害值从小到大排序,再一个个比对,一个箭杀一个兔子,用完指针后移。但是我没想到最小伤害值的箭不一定是价格最低的。所以应该是将兔子血量从大到小排序,再将箭的伤害值从大到小排序,再轮询每只兔子,找出所有能杀死当前兔子的箭,然后用这些箭中价值最低的。但是如何找当前箭中价值最低的?遍历吗?找到了之后如何删除?数组中其他数一个个往前挪吗?这样肯定会TLE的。
看了大神的,用的是优先级队列,是最符合这类问题的数据结构了。优先级队列是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素。如果不提供Comparator的话,优先队列中元素默认按自然顺序排列,也就是数字默认是小的在队列头,字符串则按字典序排列。如果想实现按照自己的意愿进行优先级排列的队列的话,需要实现Comparator接口。它的排序是堆排序,默认是最小堆,所以第一个元素永远是最小的。具体的见我下一篇博文。
将所有兔子血量从大到小,箭的伤害从大到小排序,这样对于每一只兔子可能有几只能够杀死他的箭,选择价值最小的那一个将他杀死即可,然后用当前能够杀死第二只兔子的所有箭中价值最小的去杀死第二只。。。。直到有一只兔子没有箭能够杀死它,或者把所有兔子全部杀死。这里要用到优先队列。
枚举所有兔子,将大于第一只兔子的所有箭入队列,并且按照价值从小到大,然后取出最小的杀死第一只,然后将箭伤害大于第二只兔子的所有箭入队列,当然队列里面还有能够杀死第一只兔子的箭,然后选择最小价值杀死第二只,直到队列空或者全部杀死,这样处理起来要比我那种方案方便多了。
package leetcode;
import java.io.PrintWriter;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
public class Node51_7_WipeOutRabbits {
public int solve(int n,int m,int[] B,int[][] DP){
int QB=0;
quicksortRabbit(B, 0, n-1);//倒序排兔子血量
Arrow[] arrows=new Arrow[m];
for(int i=0;i<m;i++){
arrows[i]=new Arrow(DP[i][0],DP[i][1]);
}
quicksortArrow(arrows, 0, m-1);//倒序排箭的伤害值
Comparator<Arrow> OrderIsdn = new Comparator<Arrow>(){//设置优先级队列的排序方法
public int compare(Arrow o1, Arrow o2) {
// TODO Auto-generated method stub
int numbera = o1.price;
int numberb = o2.price;
if(numbera < numberb) {
return -1;
}
else if(numbera > numberb) {
return 1;
}
else {
return 0;
}
}
};
Queue<Arrow> queue=new PriorityQueue<Arrow>(m,OrderIsdn);
int rabbitPointer=0;
int arrowPointer=0;
for(rabbitPointer=0;rabbitPointer<n;rabbitPointer++){
while(arrowPointer<m&&arrows[arrowPointer].kill>=B[rabbitPointer]){
queue.offer(arrows[arrowPointer]);
arrowPointer++;
}
if(queue.size()==0){
break;
}
else{
Arrow minPriceArrow=queue.poll();
QB+=minPriceArrow.price;
}
}
if(rabbitPointer==n){
return QB;
}
else{
return -1;
}
}
public void quicksortRabbit(int[] B,int left,int right){
if(left<right){
int low=left;
int high=right;
int pivot=B[low];
while(low<high){
while(low<high&&B[high]<=pivot){
high--;
}
if(low<high){
B[low]=B[high];
low++;
}
while(low<high&&B[low]>=pivot){
low++;
}
if(low<high){
B[high]=B[low];
high--;
}
}
B[low]=pivot;
quicksortRabbit(B, left, low-1);
quicksortRabbit(B, low+1, right);
}
}
public void quicksortArrow(Arrow[] arrows,int left,int right){
if(left<right){
int low=left;
int high=right;
Arrow pivot=arrows[low];
while(low<high){
while(low<high&&arrows[high].kill<=pivot.kill){
high--;
}
if(low<high){
arrows[low]=arrows[high];
low++;
}
while(low<high&&arrows[low].kill>=pivot.kill){
low++;
}
if(low<high){
arrows[high]=arrows[low];
high--;
}
}
arrows[low]=pivot;
quicksortArrow(arrows, left, low-1);
quicksortArrow(arrows, low+1, right);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
PrintWriter out = new PrintWriter(System.out);
int n = in.nextInt();//兔子的个数
int m = in.nextInt();//箭的种类
int[] B=new int[n];//兔子的血量
for(int i=0;i<n;i++){
B[i]=in.nextInt();
}
int[][] DP=new int[m][2];//箭的伤害值和价格
for(int i=0;i<m;i++){
DP[i]=new int[2];
DP[i][0]=in.nextInt();
DP[i][1]=in.nextInt();
}
in.close();
Node51_7_WipeOutRabbits node = new Node51_7_WipeOutRabbits();
int b = node.solve(n, m, B, DP);
if(b!=-1){
out.println(b);
}
else{
out.println("No Solution");
}
out.flush();
}
class Arrow{
int kill;
int price;
public Arrow(int kill,int price){
this.kill=kill;
this.price=price;
}
}
}