算法題型歸類整理及同類題型解法思路總結(持續更新)

1、最優路線

通用思路

1、遞歸

#案例1-最優路測路線

題目描述

評估一個網絡的信號質量,其中一個做法是將網絡劃分為柵格,然后對每個柵格的信號質量計算。

路測的時候,希望選擇一條信號最好的路線(彼此相連的柵格集合)進行演示。

現給出 R 行 C 列的整數數組 Cov,每個單元格的數值 S 即為該柵格的信號質量(已歸一化,無單位,值越大信號越好)。

要求從 [0, 0] 到 [R-1, C-1]設計一條最優路測路線。返回該路線得分。

規則:

  • 路測路線可以上下左右四個方向,不能對角
  • 路線的評分是以路線上信號最差的柵格為準的,例如路徑 8→4→5→9 的值為4,該線路評分為4。線路最優表示該條線路的評分最高。

輸入描述

一行表示柵格的行數 R

第二行表示柵格的列數 C

第三行開始,每一行表示柵格地圖一行的信號值,如5 4 5

輸出描述

最優路線的得分

備注

  • 1 ≤ R,C ≤ 20
  • 0 ≤ S ≤ 65535

用例1

輸入

3
3
5 4 5
1 2 6
7 4 6

輸出

4

說明

路線為:5→4→5→6→6

用例2

輸入

6
5
3 4 6 3 4
0 2 1 1 7
8 8 3 2 7
3 2 4 9 8
4 1 2 0 0
4 6 5 4 3

輸出

3

說明

路線為:3→4→6→3→4→7→7→8→9→4→3→8→8→3→4→4→6→5→4→3

代碼:

package algorithm.huawei;import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;public class Test61ZuiyouLuxian {static int min = Integer.MAX_VALUE;static List<List<Path>> ll = new ArrayList<List<Path>>();public static void main(String[] args) {Scanner in = new Scanner(System.in);while (in.hasNextInt()) {int m = in.nextInt();in.nextLine();int n = in.nextInt();int[][] mn = new int[m][n];for(int i=0;i<m;i++){for(int j=0;j<n;j++){mn[i][j] = in.nextInt();}in.nextLine();}int min=mn[0][0];List<Integer> li = new LinkedList<Integer>();
//			數據準備完畢dfs(mn,m,n,0,0,min,li);System.out.println(li.get(0));}}private static void dfs(int[][] mn, int m, int n, int i, int j, int min, List<Integer> li) {if(i<0 || j<0 || i>m-1 || j>n-1 || mn[i][j]==-1){return;}if(li.size()>0 && min<=li.get(0)){return;}min = Math.min(min, mn[i][j]);if(i==m-1 && j==n-1){li.clear();li.add(min);}int temp=mn[i][j];mn[i][j] = -1;//禁止走回頭路dfs(mn,m,n,i-1,j,min,li);//向上dfs(mn,m,n,i+1,j,min,li);//向下dfs(mn,m,n,i,j-1,min,li);//向左dfs(mn,m,n,i,j+1,min,li);//向右mn[i][j] = temp;//回溯		}}

#案例2-可以組成網絡的服務器

在一個機房中,服務器的位置標識在n*m的整數矩陣網格中,1表示單元格上有服務器,0表示沒有。如果兩臺服務器位于同一行或者同一列中緊鄰的位置,則認為它們之間可以組成一個局域網,請你統計機房中最大的局域網包含的服務器個數。

輸入描述

第一行輸入兩個正整數,n和m,0<n,m<=100

之后為n*m的二維數組,代表服務器信息

輸出描述

最大局域網包含的服務器個數。

示例1

輸入:
2 2
1 0
1 1輸出:
3說明: [0][0]、[1][0]、[1][1] 三臺服務器互相連接,可以組成局域網。 

代碼:

思路:

1)上下左右搜索,被搜索到的位置更新為0。

2)該題也可以使用并查集實現。【代碼附后方】

package algorithm.huawei;import java.util.Scanner;
/*案例:
3 6
1 0 1 1 0 1
1 1 1 0 0 1
1 0 1 1 0 1
9*/
/*
3 6
1 0 1 1 1 0
1 1 1 0 0 1
1 0 1 1 0 1
10*/
public class Test24Tu {public static void main(String[] args) {Scanner in = new Scanner(System.in);while (in.hasNextInt()) {int n = in.nextInt();int m = in.nextInt();in.nextLine();int[][] mn = new int[n][m];for(int i=0;i<n;i++){for(int j=0;j<m;j++){mn[i][j] = in.nextInt();}in.nextLine();}int max=0;for(int i=0;i<n;i++){for(int j=0;j<m;j++){if(mn[i][j]==0){continue;}max = Math.max(max, dfs(mn,m,n,i,j));}}System.out.println(max);}}private static int dfs(int[][] mn, int m, int n, int x, int y) {if(x<0 || y<0 || x>=n || y>=m || mn[x][y]==0){return 0;}int cnt=0;if(mn[x][y]==1){cnt=1;mn[x][y]=0;}int up=dfs(mn,m,n,x-1,y);//向上int down=dfs(mn,m,n,x+1,y);//向下int left=dfs(mn,m,n,x,y-1);//向左int right=dfs(mn,m,n,x,y+1);//向右return up+down+left+right+cnt;}}
package algorithm.huawei;import java.util.Arrays;
import java.util.Scanner;
/*案例:
3 6
1 0 1 1 0 1
1 1 1 0 0 1
1 0 1 1 0 1
9*/
/*
3 6
1 0 1 1 1 0
1 1 1 0 0 1
1 0 1 1 0 1
10*/
public class Test24Tu {public static void main(String[] args) {Scanner in = new Scanner(System.in);while (in.hasNextInt()) {int n = in.nextInt();int m = in.nextInt();in.nextLine();int[][] mn = new int[n][m];for(int i=0;i<n;i++){for(int j=0;j<m;j++){mn[i][j] = in.nextInt();}in.nextLine();}
//================方案1:遞歸求解====================//	/*int max=0;for(int i=0;i<n;i++){for(int j=0;j<m;j++){if(mn[i][j]==0){continue;}max = Math.max(max, dfs(mn,m,n,i,j));}}System.out.println(max);*///================方案2:并查集求解====================//			int[] us = new int[n*m];Arrays.fill(us, -1);for(int i=0;i<n;i++){for(int j=0;j<m;j++){int index=i*m+j;//數組下標if(mn[i][j]==1){boolean left = (j-1>=0 && mn[i][j-1]==1);//左側是否有1boolean up = (i-1>=0 && mn[i-1][j]==1);//上側是否有1if(left && up){//如果都有則進行合并,將上邊并查集合到左邊//找到左側的根int rootL = findRoot(us,index-1);//找到上側的根int rootU = findRoot(us,(i-1)*m+j);us[rootL]=us[rootL]+us[rootU]-1;us[rootU]=rootL;us[index] = rootL;}else if(left){//只有左側有則合并到左側//找到左側的根int root = findRoot(us,index-1);us[root]-=1;us[index] = root;}else if(up){//只有上側有則合并到上側//找到上側的根int root = findRoot(us,(i-1)*m+j);us[root]-=1;us[index] = root;}else{//都沒有則自己是新并查集的根us[index] = -1;}}}}int min=0;for(int i=0;i<us.length;i++){if(us[i]<0){min = Math.min(min, us[i]);}}System.out.println(-min);}}private static int findRoot(int[] us, int i) {while(us[i]>=0){i=us[i];}return i;}private static int dfs(int[][] mn, int m, int n, int x, int y) {if(x<0 || y<0 || x>=n || y>=m || mn[x][y]==0){return 0;}int cnt=0;if(mn[x][y]==1){cnt=1;mn[x][y]=0;}int up=dfs(mn,m,n,x-1,y);//向上int down=dfs(mn,m,n,x+1,y);//向下int left=dfs(mn,m,n,x,y-1);//向左int right=dfs(mn,m,n,x,y+1);//向右return up+down+left+right+cnt;}}

2、最長子串

滑動窗口、狀態打標

#案例1-出現偶數次最長子字符串的長度

題目描述

給你一個字符串 s,字符串 s 首尾相連成一個環形,請你在環中找出 'l'、'o'、'x' 字符都恰好出現了偶數次最長子字符串的長度。

輸入描述

輸入是一串小寫的字母組成的字符串

輸出描述

輸出是一個整數

1 ≤ s.length ≤ 5 * 10^5

s只包含小寫英文字母

代碼:

package algorithm.huawei;import java.util.Scanner;//思路
//經典的狀態壓縮動態規劃, 一般遇到要保存的狀態不多的問題時都可以通過狀態壓縮來解決
//注意到元音字母只有 5 個, 所以根據不同字母的奇偶性總共也就 32 個狀態
//狀態為 0 時代表[0,0,0,0,0], 表示所有元音字母都有偶數個
//狀態為 1 時代表[0,0,0,0,1], 表示只有 a 是奇數, 其余字母有偶數個
//狀態為 2 時代表[0,0,0,1,0], 表示只有 e 是奇數, 其余字母有偶數個
//...
//狀態為 31 時代表[1,1,1,1,1], 表示所有元音字母都有奇數個
//可以利用這一點, 存不同狀態下的最左邊下標, 并保存當前的狀態, 初始化狀態為 0, 因為此時各個元音字母都是 0 個, 即偶數個
//如果當前下標 i 對應的狀態已經有最左下標 j 了, 那么[j+1,i]這段區間的各個元音字母的數目一定是偶數個, 這樣才能保證 i 和 j 處的狀態相同, 如果其長度大于結果值就更新結果即可
//特別注意當狀態為 0 時本身就是合法的, 長度就是當前下標+1, 所以可以初始化該狀態的下標為-1, 這樣就可以和其他狀態下的邏輯一致了
//
public class Test12ZichuanChangdu {public static void main(String[] args) {Scanner sc = new Scanner(System.in);String input = sc.nextLine();System.out.println(getResult(input));}public static int getResult(String s) {int index = 0b000;
//    	每個下標代表一個狀態,值代表符合該狀態的第一個元素的下標int[] status = new int[8];status[0]=-1;int maxLen = 0;for (int i = 0; i < s.length() * 2; i++) {char c = s.charAt(i % s.length());switch (c) {case 'l':index ^= 0b100;break;case 'o':index ^= 0b010;break;case 'x':index ^= 0b001;break;}if (status[index] == 0) {status[index] = i;}else{maxLen = Math.max(maxLen, i-status[index]<=s.length()?i-status[index]:maxLen);}}return maxLen;}}

3、最長公共子串

動態規劃

4、最長序列

線段樹

5、四則運算

6、進出問題

通用思路

隊列、棧、雙端隊列

#案例1-籃球游戲

幼兒園里有一個放倒的圓桶,它是一個線性結構,允許在桶的右邊將籃球放入,可以在桶的左邊和右邊將籃球取出。

每個籃球有單獨的編號,老師可以連續放入 一個或多個籃球,小朋友可以在桶左邊或右邊將籃球取出,當桶里只有一個籃球的情況下,必須從左邊取出。

如老師按順序放入1、2、3、4、5 共5個編號的籃球,那么小朋友可以依次取出的編號為“1,2,3,4,5”或者“3,1,2,4,5”編號的籃球,無法取出 “5,1,3,2,4” 編號的籃球。

其中“3,1,2,4,5”的取出場景為:

  • 連續放入1,2,3號

  • 從右邊取出3號

  • 從左邊取出1號

  • 從左邊取出2號

  • 放入4號

  • 從左邊取出4號

  • 放入5號

  • 從左邊取出5號

簡單起見,我們以L表示左,R表示右,此時的籃球的依次取出序列為“ RLLLL ”

輸入描述

1、第一行的數字作為老師依次放入的籃球編號;

2、第二行的數字作為要檢查是否能夠按照放入順序取出的籃球編號;

其中籃球編號用逗號進行分隔。

輸出描述

對于每個籃球的取出序列,如果確實可以獲取,請打印出其按照左右方向的操作的取出順序,如果無法獲取則打印"NO" 。

補充說明:

  • 1<=籃球的編號,籃球個數<=200;

  • 籃球上的數字不重復;

  • 輸出的結果中LR的必須為大寫;

示例1

輸入:
4,5,6,7,0,1,2
6,4,0,1,2,5,7輸出:
RLRRRLL說明:
籃球的取出順序依次為 “右,左,右,右,右,左,左”

示例2

輸入:
4,5,6,7,0,1,2
6,0,5,1,2,4,7輸出:
NO說明:
無法取出對應序列的籃球

示例3

輸入:
1,2,3,4
1,2,3,5輸出:
NO說明:
不存在編號為5的籃球,所以無法取出對應的編號數據

代碼:

package algorithm.huawei;import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;public class Test126 {public static void main(String[] args) {Scanner in = new Scanner(System.in);while (in.hasNextLine()) {String[] sa = in.nextLine().split(",");Deque<Integer> que = new ArrayDeque<Integer>();for(int i=0;i<sa.length;i++){que.offer(Integer.parseInt(sa[i]));}String[] sa2 = in.nextLine().split(",");List<Integer> take = new ArrayList<Integer>();for(int i=0;i<sa2.length;i++){take.add(Integer.parseInt(sa2[i]));}LinkedList<Integer> ll = new LinkedList<Integer>();int takeIndex = 0;StringBuilder sb = new StringBuilder();while(!que.isEmpty() || ll.size()>0){while(que.size()>0 && (ll==null || !ll.contains(take.get(takeIndex)))){ll.add(que.poll());}if(ll.peekFirst()==take.get(takeIndex)){sb.append("L");ll.pollFirst();}else if(ll.peekLast()==take.get(takeIndex)){sb.append("R");ll.pollLast();}else{sb=new StringBuilder("NO");break;}takeIndex++;}System.out.println(sb.toString());}}}

#案例2-火車進出站

給定一個正整數N代表火車數量,0<N<10,接下來輸入火車入站的序列,一共N輛火車,每輛火車以數字1-9編號,火車站只有一個方向進出,同時停靠在火車站的列車中,只有后進站的出站了,先進站的才能出站。

要求輸出所有火車出站的方案,以字典序排序輸出。

數據范圍:1≤n≤10?

進階:時間復雜度:O(n!)?,空間復雜度:O(n)?

輸入描述:

第一行輸入一個正整數N(0 < N <= 10),第二行包括N個正整數,范圍為1到10。

輸出描述:

輸出以字典序從小到大排序的火車出站序列號,每個編號以空格隔開,每個輸出序列換行,具體見sample。

示例1

輸入:

3
1 2 3

復制輸出:

1 2 3
1 3 2
2 1 3
2 3 1
3 2 1

復制說明:

第一種方案:1進、1出、2進、2出、3進、3出
第二種方案:1進、1出、2進、3進、3出、2出
第三種方案:1進、2進、2出、1出、3進、3出
第四種方案:1進、2進、2出、3進、3出、1出
第五種方案:1進、2進、3進、3出、2出、1出
請注意,[3,1,2]這個序列是不可能實現的。  

代碼:

import java.util.*;
// 隊列表示未進站的火車
// 棧表示已進站的火車
// 每次火車進站后有兩種選擇:1.直接出站 2.等待下列火車進站  使用遞歸考慮
// 記錄和打印的遞歸函數往往是void,如果遞歸完成后還存在后續邏輯,一般情況下當前輸入變量不應受到遞歸的影響(所以當函數參數為引用類型時,遞歸的參數應當重新new出來或者深拷貝出來)
public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);while (sc.hasNext()) {int n = sc.nextInt();// 未進站的火車Queue<Integer> queue = new LinkedList<>();// 已進站的火車Stack<Integer> stack = new Stack<>();for (int i = 0; i < n; i++) {queue.offer(sc.nextInt());}List<String> outQueueList = new ArrayList<>();// 獲取所有出站隊列保存到outQueueListprocessOutQueue(queue, stack, "", outQueueList);// 排序Collections.sort(outQueueList);for (String str : outQueueList) {System.out.println(str);}}}private static void processOutQueue(Queue<Integer> queue, Stack<Integer> stack,String outQueue, List<String> outQueueList) {// 如果隊列和棧都為空,則保存出站信息if (queue.isEmpty() && stack.isEmpty()) {outQueueList.add(outQueue.trim());return;}// 二:進棧if (!queue.isEmpty()) {// 先克隆,這里全部克隆的原因是因為遞歸完回來后,不能影響我的第二種選擇// processOutQueue前面的邏輯,遞歸越深的越晚執行;processOutQueue后面的代碼(下方的出棧代碼)遞歸越深的越先執行Queue<Integer> tempQueue = new LinkedList<>(queue);Stack<Integer> tempStack = (Stack<Integer>) stack.clone();tempStack.push(tempQueue.poll());processOutQueue(tempQueue, tempStack, outQueue, outQueueList);}// 隊列和棧有兩種情況:出棧或進棧// 一:出棧if (!stack.isEmpty()) {// 先克隆Queue<Integer> tempQueue = new LinkedList<>(queue);Stack<Integer> tempStack = (Stack<Integer>) stack.clone();String tempOutQueue = outQueue + (tempStack.pop() + " ");processOutQueue(tempQueue, tempStack, tempOutQueue, outQueueList);}}
}

7、最大匹配數問題

通用思路

匈牙利匹配算法(先到先得,能讓則讓)

#案例1-素數伴侶

題目描述
若兩個正整數的和為素數,則這兩個正整數稱之為“素數伴侶”,如2和5、6和13,它們能應用于通信加密。現在密碼學會請你設計一個程序,從已有的 N ( N 為偶數)個正整數中挑選出若干對組成“素數伴侶”,挑選方案多種多樣,例如有4個正整數:2,5,6,13,如果將5和6分為一組中只能得到一組“素數伴侶”,而將2和5、6和13編組將得到兩組“素數伴侶”,能組成“素數伴侶”最多的方案稱為“最佳方案”,當然密碼學會希望你尋找出“最佳方案”。

輸入:

有一個正偶數 n ,表示待挑選的自然數的個數。后面給出 n 個具體的數字。

輸出:

輸出一個整數 K ,表示你求得的“最佳方案”組成“素數伴侶”的對數。

數據范圍:?1≤n≤100??,輸入的數據大小滿足 2≤val≤30000?

輸入描述:

輸入說明
1?輸入一個正偶數 n
2?輸入 n 個整數

輸出描述:

求得的“最佳方案”組成“素數伴侶”的對數。

示例1

輸入:

4
2 5 6 13

復制輸出:

2

復制

示例2

輸入:

2
3 6

復制輸出:

0

代碼:

import java.util.*;// 注意類名必須為 Main, 不要有任何 package xxx 信息
// 遇到遞歸出現在循環里面的,終止條件則是想辦法讓越深層的遞歸循環次數越少,直到一次循環條件都不滿足則返回默認的值
public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的區別while (in.hasNextInt()) { // 注意 while 處理多個 caseint n = in.nextInt();in.nextLine();// 奇數數組List<Integer> odds = new ArrayList<Integer>();// 偶數數組List<Integer> events = new ArrayList<Integer>();for(int i=0;i<n;i++){int var = in.nextInt();if(var%2 == 0){events.add(var);}else{odds.add(var);}}int count = 0;int[] ifMatch = new int[events.size()];for(int i=0;i<odds.size();i++){boolean[] canuse = new boolean[events.size()];Arrays.fill(canuse,true);if(dfs(odds.get(i),events,ifMatch,canuse)){count++;};}System.out.println(count);}}public static boolean dfs(int x,List<Integer> events,int[] ifMatch,boolean[] canuse) {for(int i=0;i<events.size();i++){// 先到先得:如果該位置能用且符合素數且該位置沒被占用則可以占用if(canuse[i] && isPrime(x+events.get(i))){canuse[i] = false;//把位置改為不可用if(ifMatch[i]==0 || dfs(ifMatch[i],events,ifMatch,canuse)){//如果該位置沒被占用,或者被占用了但是占用的odd能重新找到其他event進行匹配,則可以使用ifMatch[i] = x;return true;}}}return false;}public static boolean isPrime(int x) {for(int i=2;i<=Math.sqrt(x);i++){if(x%i==0){return false;}}return true;}
}

#案例2-矩陣匹配

題目描述

從一個 N * M(N ≤ M)的矩陣中選出 N 個數,任意兩個數字不能在同一行或同一列,求選出來的 N 個數中第 K 大的數字的最小值是多少。

輸入描述

輸入矩陣要求:1 ≤ K ≤ N ≤ M ≤ 150

輸入格式:

N M K

N*M矩陣

輸出描述

N*M 的矩陣中可以選出 M! / N! 種組合數組,每個組合數組種第 K 大的數中的最小值。無需考慮重復數字,直接取字典排序結果即可。

備注

注意:結果是第 K 大的數字的最小值

代碼:

思路:每一個行號只能跟一個列號匹配,我們可以利用二分法枚舉第k大的值,然后通過匈牙利算法檢查符合條件的且小于這個值的匹配數量是否滿足要求,如果滿足則說明枚舉值kth給大了,如果不滿足說明枚舉值kth給小了。

import java.util.Arrays;
import java.util.Scanner;public class Main {static int n;static int m;static int k;static int[][] matrix;public static void main(String[] args) {Scanner sc = new Scanner(System.in);n = sc.nextInt();m = sc.nextInt();k = sc.nextInt();int min = 1;int max = Integer.MIN_VALUE;matrix = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {matrix[i][j] = sc.nextInt();max = Math.max(max, matrix[i][j]);}}// 二分枚舉第K大值while (min <= max) {// mid就是被枚舉出來的N個數中的第K大值int mid = (min + max) >> 1;// 檢查mid作為N個數中第K大值時,是否存在N-K+1個不大于它的值if (check(mid)) {max = mid - 1;} else {min = mid + 1;}}System.out.println(min);}public static boolean check(int kth) {// 利用二分圖最大匹配來求解,小于等于kth(第K大值)的元素個數(即二分圖最大匹配)int smallerCount = 0;// 記錄每個列號的匹配成功的行號int[] match = new int[m];// 初始時每個列號都處于未配對狀態,此時將列號配對的行號賦值為-1Arrays.fill(match, -1);// 遍歷行號,每個行號對互相心儀的列號發起配對請求for (int i = 0; i < n; i++) {// 記錄增廣路訪問過的列號boolean[] vis = new boolean[m];if (dfs(i, kth, match, vis)) smallerCount++;}return smallerCount >= n - k + 1;}public static boolean dfs(int i, int kth, int[] match, boolean[] vis) {// 行號 i 發起了配對請求// 遍歷每一個列號jfor (int j = 0; j < m; j++) {// 如果當前列號j未被增廣路探索過 && 當前列j行i可以配對(如果行列號位置(i,j)對應矩陣元素值小于等于kth(第K大值),則可以配對)if (!vis[j] && matrix[i][j] <= kth) {vis[j] = true;// 如果對應列號j未配對,或者,已配對但是配對的行號match[j]可以找到其他列號重新配對if (match[j] == -1 || dfs(match[j], kth, match, vis)) {// 則當前行號i 和 列號j 可以配對match[j] = i;return true;}}}return false;}
}

本案例參考&鳴謝:

華為OD機試 - 矩陣匹配(Java & JS & Python & C & C++)_od 矩陣匹配-CSDN博客

8、分配方案的最大效益問題

通用思路:

1)PriorityQueue:堆的使用。

2)動態規劃:不關心具體方案,只關心最值情況優先考慮動態規劃的可能。

#案例1-貪心歌手

一個歌手準備從A城去B城參加演出

  1. 按照合同,他必須在T天內趕到
  2. 歌手不能往回走
  3. 每兩座城市之間需要的天數都可以提前獲知。
  4. 歌手在每座城市都可以在路邊賣唱賺錢。經過調研,歌手提前獲知了每座城市賣唱的收入預期: 如果在一座城市第一天賣唱可以賺M,后續每天的收入會減少D(第二天賺的錢是M - D,第三天是M-2D…)如果收入減到0就不會再少了。
  5. 歌手到達后的第二天才能開始賣唱。如果今天賣過唱,第二天才能出發

貪心的歌手最多可以賺多少錢?

輸入描述

第一行兩個數字 TN,中間用空格隔開 T 代表總天數; N 代表路上經過N座城市; 0 < T < 1000 ,0 < N < 100

第二行N+1個數字,中間用空格隔開 代表每兩座城市之間耗費的時間。 其總和<=T

接下來N行,每行兩個數字MD,中間用空格隔開.

代表每個城市的收入預期。

0< M <1000, 0 < D < 100

輸出描述

一個數字。代表歌手最多可以賺多少錢。以回車結束

示例1

輸入:
10 2
1 1 2
120 20
90 10輸出:
540說明:
總共10天,路上經過2座城市。 路上共花1+1+2=4天 剩余6天最好的計劃是
在第一座城市待3天,在第二座城市待3天 在第一座城市賺的錢:120+100+80=300 
在第二座城市賺的錢:90+80+70=240 
一共300+240 = 540

代碼:

思路:

1)每次都待預期收入最高的城市,待完更新該城市的最新預期。

2)數據結構堆的使用,每次放入數據都會按比較器定義的大小順序進行放入。

package algorithm.huawei;import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Scanner;public class Test82 {public static void main(String[] args) {Scanner in = new Scanner(System.in);while (in.hasNextInt()) {int t = in.nextInt();//t天int n = in.nextInt();//n個城市in.nextLine();int route = 0;//路上耗時for(int i=0;i<n+1;i++){route+=in.nextInt();}in.nextLine();City[] citys = new City[n];PriorityQueue<City> pq = new PriorityQueue<City>((c1,c2)->c2.fee-c1.fee);for(int i=0;i<n;i++){int fee=in.nextInt();int q=in.nextInt();City city = new City(fee,q);pq.add(city);in.nextLine();}
//			Arrays.sort(citys,(c1,c2)->c2.fee-c1.fee);int max=0;int i=0;int k=0;//當前城市待的天數int lest = t-route;//剩余天數while(lest>0){lest--;City city = pq.poll();int fee=city.fee;int q=city.q;max+=fee;city.fee=fee-q;pq.add(city);}System.out.println(max);}}}class City{int fee;int q;public City(int fee, int q) {super();this.fee = fee;this.q = q;}}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/41972.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/41972.shtml
英文地址,請注明出處:http://en.pswp.cn/web/41972.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

12種增強Python代碼的函數式編程技術

前言 什么是函數式編程&#xff1f; 一句話總結&#xff1a;函數式編程(functional programming)是一種編程范式&#xff0c;之外還有面向對象&#xff08;OOP&#xff09;、面向過程、邏輯式編程等。 函數式編程是一種高度抽象的編程范式&#xff0c;它倡導使用純函數&#x…

算法·二分

二分枚舉 適用條件&#xff1a; 答案有明顯上下界答案具有單調性:a滿足,若b>a可以知b必定滿足。本質上是枚舉的對數優化 思維技巧 解決問題->>驗證答案,明顯前者比后者更加困難若題目有最大值最小&#xff0c;最小值最大這種經典條件&#xff0c;隱含著答案有界 …

Docker-11☆ Docker Compose部署RuoYi-Cloud

一、環境準備 1.安裝Docker 附:Docker-02-01☆ Docker在線下載安裝與配置(linux) 2.安裝Docker Compose 附:Docker-10☆ Docker Compose 二、源碼下載 若依官網:RuoYi 若依官方網站 鼠標放到"源碼地址"上,點擊"RuoYi-Cloud 微服務版"。 跳轉至G…

深入理解計算機系統 CSAPP 家庭作業8.22

書本知識夠你寫出答案,但是如果你想驗證你寫的答案,就要一些額外的東西.這本書很多題目都是如此 /** mysystem.c*/ #include <stdio.h> #include "csapp.h"int mysystem(char* command) {pid_t pid;int status;if ((pid Fork()) 0) {/*這里是關鍵用子程序去…

新加坡工作和生活指北:工作篇

文章首發于公眾號&#xff1a;Keegan小鋼 一年多以前&#xff08;2022 年 8 月初&#xff09;&#xff0c;那時我過來新加坡才 4 個多月&#xff0c;就寫了篇文章分享了當時在新加坡的生活和工作體驗。文章得到的反響不錯&#xff0c;但也反饋出了一些新的問題&#xff0c;比如…

預訓練對齊:數學理論到工程實踐的橋梁

在人工智能和機器學習領域&#xff0c;預訓練模型的對齊是一個至關重要的概念。本篇博客源自聽了一場黃民烈老師關于大模型對齊的分享&#xff0c;整理內容如下&#xff0c;供大家參考。 數學理論中的預訓練對齊 數學理論上&#xff0c;預訓練對齊是什么&#xff1f; 序列…

Java-關鍵字(static,final)

1.1 static關鍵字 static關鍵字 : 靜態的意思 , 可以修飾變量 , 也可以修飾方法 , 被static修飾的成員 , 我們叫做靜態成員 static特點 : 靜態成員被所類的所有對象共享 隨著類的加載而加載 , 優先于對象存在 可以通過對象調用 , 也可以通過類名調用 , 建議使用類名 1. 靜…

Keepalived+HAProxy 集群及虛IP切換實踐

1、軟件介紹 ①Keepalived keepalive是一個用c語言編寫的路由軟件&#xff0c;這個項目的主要目標是為Linux系統和基于Linux的基礎設施提供簡單而健壯的負載平衡和高可用性設施。負載均衡框架依賴于眾所周知且廣泛使用的Linux Virtual Server (IPVS)內核模塊提供第4層負載均衡…

srs直播內網拉流帶寬飆升問題記錄

問題背景 srs部署在云服務器上&#xff0c;32核cpu&#xff0c;64G內存&#xff0c;帶寬300M. 客戶端從srs拉流&#xff0c;發現外網客戶端拉流&#xff0c;cpu和帶寬都正常。然而內網客戶端拉流&#xff0c;拉流人數超過5人以上&#xff0c;帶寬就會迅速飆升。 排查 用srs…

數學建模論文寫作文檔word

目錄 1. 摘要寫法1.1 確定題目與方法1.2 編寫開頭段落1.3 填寫問題一1.4 重復步驟3填寫其他問題1.5 編寫結尾段落1.6 編寫關鍵詞 2. 問題重述2.1 問題背景2.2 問題提出 3. 問題分析4. 問題X模型的建立與求解5. 模型的分析5.1 靈敏度分析5.2 誤差分析&#xff08;主要用于預測類…

Milvus lite start 及存儲策略

背景 今天開始寫下Milvus&#xff0c;為了方便&#xff0c;我直接使用的是 milvus-lite 版本&#xff0c;default 情況下&#xff0c;你可能不知道他到底將 db 存儲到什么位置了。啟動 default-server&#xff0c;看下Milvus 的start及存儲邏輯 主邏輯 def start(self):sel…

adb參數詳解

文章目錄 1. -d2. -e3. -s4. -t5. -H6. -P7. -L8. --one-device9. --exit-on-write-error10. connect / disconnect11. pair12. forward13. forward --list14. reverse15. mdns check16. mdns services17. push18. pull19. sync20.shell21. install22. uninstall23. bugreport2…

最小二乘支持向量機(Least Squares Support Vector Machine,LSSVM)及其Python和MATLAB實現

LSSVM&#xff08;Least Squares Support Vector Machine&#xff09;又稱最小二乘支持向量機&#xff0c;是支持向量機&#xff08;SVM&#xff09;的一種變體&#xff0c;它通過將SVM的優化問題轉化為帶約束的二次規劃問題&#xff0c;利用最小二乘法進行優化求解&#xff0c…

redis集群部署 (通過redis工具快速部署,手動部署)

目錄 一、快速部署集群 1、 進入集群目錄&#xff0c;創建集群 2、 查看正常啟動 二、部署集群 1、分配集群節點 2、驗證集群可用性 3、停止redis進程 三、手動部署集群 1、配置redis.conf配置文件 2、啟動redis集群 3、手動創建redis集群 4、驗證 四、集群…

mysql異常數據損壞處理,報錯:Operating system error number 2 in a file operation

一、問題描述 某次一線反應&#xff0c;某主庫表全部丟失&#xff0c;查看為空&#xff0c;登陸主機查看mysqld.log后報錯&#xff1a;Operating system error number 2 in a file operation數據目錄OS重裝后修改過&#xff0c;但只是指向方式不同&#xff0c;目錄還是同一目錄…

【綠色版】Mysql下載、安裝、配置與使用(保姆級教程)

大家都知道&#xff0c;Mysql安裝版的卸載過程非常繁瑣&#xff0c;而且卸載不干凈會出現許多問題&#xff0c;很容易讓大家陷入重裝系統的窘境。基于此&#xff0c;博主今天給大家分享綠色版Mysql的安裝、配置與使用。 目錄 一、Mysql安裝、配置與使用 1、下載解壓 2、創建…

vue對axios進行請求響應封裝

一、原因 像是在一些業務邏輯上&#xff0c;比如需要在請求之前展示loading效果&#xff0c;或者在登錄的時候判斷身份信息&#xff08;token&#xff09;等信息有沒有過期&#xff0c;再者根據服務器響應回來的code碼進行相應的提示信息。等等在請求之前&#xff0c;之后做的一…

ABAP注釋快捷鍵修改(留著備用)

ABAP注釋快捷鍵修改(留著備用) 在使用ABAP編輯器的時候&#xff0c;原有的添加代碼注釋和取消代碼注釋的快捷鍵未生效&#xff0c;這時我們可以考慮對注釋快捷鍵進行修改 在事務碼SE38(ABAP編輯器)屏幕右下角&#xff0c;點擊【Options選項】圖標 在【鍵盤】|【命令】輸入欄中…

DWM 相關實現代碼 [自用]

1. DWM 縮略圖和模糊隱藏實現半透明 #include <windows.h> #include <dwmapi.h> #include <string> #pragma comment(lib, "dwmapi.lib")// 檢查 UWP 窗口是否可見 bool IsUWPWindowVisible(HWND hwnd) {DWORD cloaked 0;DwmGetWindowAttribute(…

【c語言】玩轉文件操作

&#x1f31f;&#x1f31f;作者主頁&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所屬專欄&#xff1a;C語言 目錄 引言 一、文件的打開和關閉 1.流 2.標準流 3.文本文件和二進制文件 4.控制文件打開與關閉的函數 二、文件的順序讀寫 三、文件的隨機讀寫 1…