链接:https://ac.nowcoder.com/acm/contest/5246/A
来源:牛客网
题目描述
小招在玩一款游戏:在一个N层高的金字塔上,以金字塔顶为第一层,第i层有i个落点,每个落点有若干枚金币,在落点可以跳向左斜向下或向右斜向下的落点。若知道金字塔的层数N及每层的金币数量分布,请计算小招在本次游戏中可以获得的最多金币数量。
输入描述:
输入共有N + 1行(N ≤ 1024),第一行为高度N,第二行至N + 1行 ,为该金字塔的金币数量分布。
输出描述:
输出金币数量。
示例1
输入
复制
5
8
3 8
8 1 0
4 7 5 4
3 5 2 6 5
输出
复制
31
开始没看懂题目,样例怎么算都是34,不是31啊?
后来看到这是个金字塔,虽然输入的是个直角三角形,其实应该是个等腰三角形:
8
3 8
8 1 0
4 7 5 4
3 5 2 6 5
这样改了代码之后就没问题了
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int N = in.nextInt();
long[] b = new long[N*(N+1)/2];
int count = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j <= i; j++) {
// b[count++] = in.nextLong();
b[count++] = new Random().nextInt(20);
}
}
// System.out.println(Arrays.toString(b));
System.out.println(maxOfCoins(b,N));
System.out.println(maxOfCoins2(b,N));
in.close();
}
private static long maxOfCoins(long[] b, int n) {
long[][] p = new long[n][n];
int count = 0;
p[0][0] = b[count++];
for (int i = 1; i < n; i++) {
for (int j = 0; j <= i; j++) {
count = i*(i+1)/2+j;
long temp = 0;
if(j==0) {
p[i][j] = b[count++]+ p[i-1][j];
continue;
}
if(j==i) {
p[i][j] = b[count++]+ p[i-1][j-1];
continue;
}
temp = Math.max(p[i-1][j],p[i-1][j-1]);
p[i][j] = temp + b[count++];
}
}
long max = 0;
for (int i = 0; i < n; i++) {
max = Math.max(p[n-1][i],max);
}
return max;
}
}
看了别人的代码,这题从底层往上动态规划更简单。
把原C代码改成了java的
private static long maxOfCoins2(long[] b, int n) {
long[][] a = new long[n][n];
long[][] f = new long[n][n];
int count = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j <= i; j++) {
a[i][j] = b[count++];
}
}
for (int j = 0; j <n; j++) {
f[n-1][j] = a[n-1][j];
}
for (int i = n-2; i >=0; i--) {
for (int j = 0; j <=i; j++) {
f[i][j] = a[i][j]+Math.max(f[i+1][j],f[i+1][j+1]);
}
}
return f[0][0];
}
链接:https://ac.nowcoder.com/acm/contest/5246/B
来源:牛客网
题目描述
在一场集体婚礼上,有n对新人需要坐在连续排列的 2n个座位上合影,同一对新人彼此挨着。由于进场时各对新人并未按序入座,请计算最少交换座位的次数,以便使每对新人均可并肩坐在一起。一次交换可选择任意两人,让他们互换座位。
全部新人的序号可用 0 到 2n-1 的整数表示,第一对是 (0, 1),第二对是 (2, 3),以此类推,最后一对是 (2n-2, 2n-1)。
row[i]指最初坐在第 i 个座位上的新人编号,i是从0到(2n-1)的一个升序全排列,row不存在重复值。
输入描述:
输入共有2行,第一行为n,即共有多少对新人(2≤n≤100000 ),第二行为row,即2n个座位上的初始新人编号。
输出描述:
输出最少交换座位的次数。
示例1
输入
复制
2
0 2 1 3
输出
1
说明
我们只需要交换1和2的位置即可
示例2
输入
2
3 2 0 1
输出
0
说明
无需交换座位,所有的新人都已经并肩坐在一起
和leetcode765相同
第9行的continue忘了写,我自己都不敢信,debug好久。。。还是太菜
private static int numOfSwap(int[] pair, int n) {
int i=0;
int j ;
int sum = 0;
while (i<2*n){
int target = pair[i]^0x01;
if (pair[i+1]==target){
i+=2;
continue;
}
j=i;
while (++j<2*n){
if (pair[j]==target){
pair[j] = pair[i+1];
pair[i+1] = target;
sum++;
break;
}
}
i+=2;
}
return sum;
}
官方题解的方法2(方法1回溯超时没看,方法3是贪心)
思路 假设 ”快乐交换理论“
是对的,如果一对情侣不坐在一对沙发上,那么就有两种交换的选择将这张沙发上凑成一对情侣。对于这样的交换,其实可以把它化成一张图,举个例子,有沙发
X 和 沙发 Y(可能是同一个沙发),可以通过画一条 X 到 Y 的无向边来表示 X 沙发跟 Y
沙发上可以组成一对情侣。这样最后画成的图把它称作情侣图,这张图每个节点的度为2,图上有一些连通分量。每次将一个沙发上凑成一对情侣之后,在图上的变化是多了一个自循环的连通分量。我们的目标是让图中有 N
个连通分量,每个连通分量代表一对情侣。每次交换都会将连通分量的数量增加 1,根据 ”快乐交换理论“,问题的答案可以通过 N
减去最开始情侣图中连通分量的个数来得到。现在来证明 ”快乐交换理论“
是正确的,可以观察到不论怎么交换,一次交换都不可能增加多于一个连通分量,所以每次增加一个连通分量的交换就是最优解。(同时这也可以证明方法一中的假设,因为不管按什么顺序去增加连通分量,结果都不会改变)算法
首先来构建图,定义 adj[node] 为当前 node
的情侣所处沙发的下标。随后找到所有的联通分量。最后让每个沙发变成一个自循环的连通分量。class Solution { public int minSwapsCouples(int[] row) { int N = row.length / 2; //couples[x] = {i, j} means that //couple #x is at couches i and j (1 indexed) int[][] couples = new int[N][2]; for (int i = 0; i < row.length; ++i) add(couples[row[i]/2], i/2 + 1); //adj[x] = {i, j} means that //x-th couch connected to couches i, j (all 1 indexed) by couples int[][] adj = new int[N+1][2]; for (int[] couple: couples) { add(adj[couple[0]], couple[1]); add(adj[couple[1]], couple[0]); } // The answer will be N minus the number of cycles in adj. int ans = N; // For each couch (1 indexed) for (int r = 1; r <= N; ++r) { // If this couch has no people needing to be paired, continue if (adj[r][0] == 0 && adj[r][1] == 0) continue; // Otherwise, there is a cycle starting at couch r. // We will use two pointers x, y with y faster than x by one turn. ans--; int x = r, y = pop(adj[r]); // When y reaches the start 'r', we've reached the end of the cycle. while (y != r) { // We are at some couch with edges going to 'x' and 'new'. // We remove the previous edge, since we came from x. rem(adj[y], x); // We update x, y appropriately: y becomes new and x becomes y. x = y; y = pop(adj[y]); } } return ans; } // Replace the next zero element with x. public void add(int[] pair, int x) { pair[pair[0] == 0 ? 0 : 1] = x; } // Remove x from pair, replacing it with zero. public void rem(int[] pair, int x) { pair[pair[0] == x ? 0 : 1] = 0; } // Remove the next non-zero element from pair, replacing it with zero. public int pop(int[] pair) { int x = pair[0]; if (x != 0) { pair[0] = 0; } else { x = pair[1]; pair[1] = 0; } return x; } }
复杂度分析
时间复杂度: O(N)O(N),其中 NN 情侣对的数量。
空间复杂度: O(N)O(N)。
作者:LeetCode
链接:https://leetcode-cn.com/problems/couples-holding-hands/solution/qing-lu-qian-shou-by-leetcode/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
leetcode用户题解:
解题思路 union find 情侣两两一组,如果row[i] 和 row[i + 1]
不原来不在一个组,就把它放入一个组里,每个组里面的个数都是偶数。每当减少一个组了,就代表需要多交换一次。
代码
java class Solution { public int minSwapsCouples(int[] row) { int res = 0; int n = row.length; int[] root = new int[n]; for (int i = 0; i < n; i ++) { root[i] = i; } for (int i = 0; i < n; i += 2) { int x = find(root, row[i] / 2); int y = find(root, row[i + 1] / 2); if (x != y) { root[x] = y; res ++; } } return res; } int find (int[] root, int idx) { while (root[idx] != idx) return find(root, root[idx]); return idx; } }
作者:don-vito-corleone
链接:https://leetcode-cn.com/problems/couples-holding-hands/solution/java-union-find-by-don-vito-corleone/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
链接:https://ac.nowcoder.com/acm/contest/5246/C 来源:牛客网
题目描述
小招正在玩一款修塔游戏:系统中有n座高塔,每座高塔由若干个高度相同的方块堆砌而成。修塔游戏的规则为:
(1)每次从最高塔的塔尖拿走一个方块
(2)每次在最低塔的塔尖堆砌一个方块
小招每次只能完成上述两个动作中的一个动作。游戏的目标是使n座高塔中至少有k座高塔的高度相同,请问小招最少需要多少次才能完成游戏。 输入描述:
输入共有2行,第一行为n和k(1≤k≤n≤200000 ),第二行为n座塔的高度组成的数组 a1, a2,
…an(1≤aj≤10000)。
输出描述: 输出值为最少需要多少次动作才能完成游戏。 示例1 输入 6 5 1 2 2 4 2 3 输出 3
参考题解:(有问题,通过率0)
思路主要是: (1)先排序,然后分两条路径。
(2)正向将第k个值以前的值都改成与第k个值相同的值。然后看第k个位置之后如果有和arr[k]相同的值的话,就是多走了,再减下去。
(3)反向亦然。public class test03 { public static void main(String[] args) { Scanner scan=new Scanner(System.in); int N=scan.nextInt(); int k=scan.nextInt(); scan.nextLine(); int [] arr=new int[N]; for(int i=0;i<N;i++){ arr[i]=scan.nextInt(); } Arrays.sort(arr); int result = beginGame(arr, N, k); System.out.println(result); } private static int beginGame(int[] arr, int N, int k) { int path1 = 0; int path2 = 0; for (int i=0;i<k;i++){ path1+=arr[k-1]-arr[i]; path2+=arr[N-i-1]-arr[N-k]; } int index1=k; int index2=N-k-1; while(index1<N&&arr[index1++]==arr[k-1]){ path1--; } while(index2>=0&&arr[index2--]==arr[N-k]){ path2--; } return Math.min(path1, path2); } }
版权声明:本文为CSDN博主「JAVA小摩托不堵车」的原创文章,遵循CC 4.0
BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42924812/article/details/105836102