You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
6.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class27;
import java.util.Arrays;
public class Code01_PickBands {
// 每一个项目都有三个数,[a,b,c]表示这个项目a和b乐队参演花费为c
// 每一个乐队可能在多个项目里都出现了,但是只能挑一次
// nums是可以挑选的项目数量所以一定会有nums*2只乐队被挑选出来
// 乐队的全部数量一定是nums*2且标号一定是0 ~ nums*2-1
// 返回一共挑nums轮(也就意味着一定请到所有的乐队),最少花费是多少?
public static int minCost(int[][] programs, int nums) {
if (nums == 0 || programs == null || programs.length == 0) {
return 0;
}
int size = clean(programs);
int[] map1 = init(1 << (nums << 1));
int[] map2 = null;
if ((nums & 1) == 0) {
// nums = 8 , 4
f(programs, size, 0, 0, 0, nums >> 1, map1);
map2 = map1;
} else {
// nums == 7 4 -> map1 3 -> map2
f(programs, size, 0, 0, 0, nums >> 1, map1);
map2 = init(1 << (nums << 1));
f(programs, size, 0, 0, 0, nums - (nums >> 1), map2);
}
// 16 mask : 0..00 1111.1111(16个)
// 12 mask : 0..00 1111.1111(12个)
int mask = (1 << (nums << 1)) - 1;
int ans = Integer.MAX_VALUE;
for (int i = 0; i < map1.length; i++) {
if (map1[i] != Integer.MAX_VALUE && map2[mask & (~i)] != Integer.MAX_VALUE) {
ans = Math.min(ans, map1[i] + map2[mask & (~i)]);
}
}
return ans == Integer.MAX_VALUE ? -1 : ans;
}
// [
// [9, 1, 100]
// [2, 9 , 50]
// ...
// ]
public static int clean(int[][] programs) {
int x = 0;
int y = 0;
for (int[] p : programs) {
x = Math.min(p[0], p[1]);
y = Math.max(p[0], p[1]);
p[0] = x;
p[1] = y;
}
Arrays.sort(programs, (a, b) -> a[0] != b[0] ? (a[0] - b[0]) : (a[1] != b[1] ? (a[1] - b[1]) : (a[2] - b[2])));
x = programs[0][0];
y = programs[0][1];
int n = programs.length;
// (0, 1, ? )
for (int i = 1; i < n; i++) {
if (programs[i][0] == x && programs[i][1] == y) {
programs[i] = null;
} else {
x = programs[i][0];
y = programs[i][1];
}
}
int size = 1;
for (int i = 1; i < n; i++) {
if (programs[i] != null) {
programs[size++] = programs[i];
}
}
// programs[0...size-1]
return size;
}
public static int[] init(int size) {
int[] arr = new int[size];
for (int i = 0; i < size; i++) {
arr[i] = Integer.MAX_VALUE;
}
return arr;
}
public static void f(int[][] programs, int size, int index, int status, int cost, int rest, int[] map) {
if (rest == 0) {
map[status] = Math.min(map[status], cost);
} else {
if (index != size) {
f(programs, size, index + 1, status, cost, rest, map);
int pick = 0 | (1 << programs[index][0]) | (1 << programs[index][1]);
if ((pick & status) == 0) {
f(programs, size, index + 1, status | pick, cost + programs[index][2], rest - 1, map);
}
}
}
}
// // 如果nums2 * nums 只乐队
// // (1 << (nums << 1)) - 1
// // programs 洗数据 size
// // nums = 8 16只乐队
//
// // process(programs, size, (1 << (nums << 1)) - 1, 0, 4, 0, 0)
//
// public static int minCost = Integer.MAX_VALUE;
//
// public static int[] map = new int[1 << 16]; // map初始化全变成系统最大
//
//
//
// public static void process(int[][] programs, int size, int index, int rest, int pick, int cost) {
// if (rest == 0) {
//
// map[pick] = Math.min(map[pick], cost);
//
// } else { // 还有项目可挑
// if (index != size) {
// // 不考虑当前的项目programs[index];
// process(programs, size, index + 1, rest, pick, cost);
// // 考虑当前的项目programs[index];
// int x = programs[index][0];
// int y = programs[index][1];
// int cur = (1 << x) | (1 << y);
// if ((pick & cur) == 0) { // 终于可以考虑了!
// process(programs, size, index + 1, rest - 1, pick | cur, cost + programs[index][2]);
// }
// }
// }
// }
//
//
// public static void zuo(int[] arr, int index, int rest) {
// if(rest == 0) {
// 停止
// }
// if(index != arr.length) {
// zuo(arr, index + 1, rest);
// zuo(arr, index + 1, rest - 1);
// }
// }
// 为了测试
public static int right(int[][] programs, int nums) {
min = Integer.MAX_VALUE;
r(programs, 0, nums, 0, 0);
return min == Integer.MAX_VALUE ? -1 : min;
}
public static int min = Integer.MAX_VALUE;
public static void r(int[][] programs, int index, int rest, int pick, int cost) {
if (rest == 0) {
min = Math.min(min, cost);
} else {
if (index < programs.length) {
r(programs, index + 1, rest, pick, cost);
int cur = (1 << programs[index][0]) | (1 << programs[index][1]);
if ((pick & cur) == 0) {
r(programs, index + 1, rest - 1, pick | cur, cost + programs[index][2]);
}
}
}
}
// 为了测试
public static int[][] randomPrograms(int N, int V) {
int nums = N << 1;
int n = nums * (nums - 1);
int[][] programs = new int[n][3];
for (int i = 0; i < n; i++) {
int a = (int) (Math.random() * nums);
int b = 0;
do {
b = (int) (Math.random() * nums);
} while (b == a);
programs[i][0] = a;
programs[i][1] = b;
programs[i][2] = (int) (Math.random() * V) + 1;
}
return programs;
}
// 为了测试
public static void main(String[] args) {
int N = 4;
int V = 100;
int T = 10000;
System.out.println("测试开始");
for (int i = 0; i < T; i++) {
int nums = (int) (Math.random() * N) + 1;
int[][] programs = randomPrograms(nums, V);
int ans1 = right(programs, nums);
int ans2 = minCost(programs, nums);
if (ans1 != ans2) {
System.out.println("Oops!");
break;
}
}
System.out.println("测试结束");
long start;
long end;
int[][] programs;
programs = randomPrograms(7, V);
start = System.currentTimeMillis();
right(programs, 7);
end = System.currentTimeMillis();
System.out.println("right方法在nums=7时候的运行时间(毫秒) : " + (end - start));
programs = randomPrograms(10, V);
start = System.currentTimeMillis();
minCost(programs, 10);
end = System.currentTimeMillis();
System.out.println("minCost方法在nums=10时候的运行时间(毫秒) : " + (end - start));
}
}