动态规划进阶习题——左孩子右兄弟、取气球【算法赛】、大臣的旅费、蓝桥舞会、树的连边II、糖果

发布时间:2026/7/21 7:02:04
动态规划进阶习题——左孩子右兄弟、取气球【算法赛】、大臣的旅费、蓝桥舞会、树的连边II、糖果 左孩子右兄弟题目描述对于一棵多叉树我们可以通过 “左孩子右兄弟” 表示法将其转化成一棵二叉树。如果我们认为每个结点的子结点是无序的那么得到的二叉树可能不唯一。换句话说每个结点可以选任意子结点作为左孩子并按任意顺序连接右兄弟。给定一棵包含 NN​​ 个结点的多叉树结点从 11​​ 至 NN​ 编号其中 11 号结点是根每个结点的父结点的编号比自己的编号小。请你计算其通过 “左孩子右兄弟” 表示法转化成的二叉树高度最高是多少。注只有根结点这一个结点的树高度为 00​。输入描述输入的第一行包含一个整数 NN​​​。 以下 N−1N−1​​ 行每行包含一个整数依次表示 22​ 至 NN 号结点的父结点编号。输出描述输出一个整数表示答案。输入输出样例示例 1输入5 1 1 1 2输出4评测用例规模与约定对于 30%30%​​ 的评测用例1≤N≤201≤N≤20​对于所有评测用例1≤N≤1000001≤N≤100000。import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.*; public class Main { static int N100010; static int n,m; static int f[]new int[N];//表示以i为根结点时所能形成的最高的二叉树的高度 static int p[]new int[N];//表示i的父节点 static int maxf[]new int[N];//表示以i为根结点时的子数中他所有的子节点中以不同子节点为根的子树最大高度 static int sonnum[]new int[N];//节点i的子节点的数量 static char c[]; static BufferedReader br new BufferedReader(new InputStreamReader(System.in)); static BufferedWriter bwnew BufferedWriter(new OutputStreamWriter(System.out)); public static void main(String[] args) throws IOException { StringTokenizer stnew StringTokenizer(br.readLine()); nInteger.parseInt(st.nextToken()); for (int i 2; i n; i) { stnew StringTokenizer(br.readLine()); p[i]Integer.parseInt(st.nextToken()); sonnum[p[i]]; } for (int i n; i 0; i--) {//在处理一个节点的时候必须保证它的子节点全部都处理过 f[i]sonnum[i]maxf[i]; int parentp[i]; maxf[parent]Math.max(maxf[parent], f[i]); } bw.write(f[1]); br.close(); bw.flush(); bw.close(); } }取气球【算法赛】问题描述为庆祝蓝桥周赛的举办大厅中挂满了 nn 个填充空气的气球。第 11 号气球被粘在天花板上其他气球则用绳子挂在比它编号小的气球上。为了防止气球被扯破每个气球上方最多只能连着一根绳子。小明觉得气球太多了于是决定拿走一些。小明有两种方式可以拿走气球割断一根绳子这根绳子下方的所有气球都会掉落。小明可以将这些气球全部拿走。戳破一个气球这根气球下方的所有气球都会掉落。当然被戳破的气球本身是无法拿走的。由于主办方财大气粗每一根绳子和每一个气球都采用了不同的材料。对于第 ii 根绳子小明需要花费 wiwi​ 的力气来割断它。对于第 jj 个气球小明需要花费 ajaj​ 的力气来戳破它。小明最多能使出 WW 点力气他想知道他最多能拿走多少个气球。输入格式第一行包含两个整数 n,Wn,W代表有 nn 个气球, 小明最多能使出 WW 点力气。1≤n,W≤50001≤n,W≤5000。接下来一行包含 nn 个整数 a1,a2,…,ana1​,a2​,…,an​表示戳破每个气球需要的力气。1≤ai≤5×1031≤ai​≤5×103。接下来 n−1n−1 行每行包含 22 个整数 {ui,wi}{ui​,wi​} , 表示编号为 i1i1 的气球上端连着第 uiui​ 个气球割断这根绳子需要 wiwi​ 点力气。1≤ui≤n,1≤wi≤5×1031≤ui​≤n,1≤wi​≤5×103。输出格式输出仅一行包含一个整数表示答案。样例输入8 6 9 6 1 2 1 1 2 1 1 5 1 1 1 5 2 2 2 1 4 1 4 2样例输出5说明花 22 点力气割断第气球 22 和气球 55 之间的绳子获得 55 这一个气球。花 11 点力气割断第气球 22 和气球 66 之间的绳子获得 66 这一个气球。花 11 点力气割断第气球 11 和气球 33 之间的绳子获得 33 这一个气球。花 22 点力气割戳破气球 44获得 77 和 88 两个气球。故样例输出 55 。import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.*; public class Main { static int N5*1010; static int n,w; static int id1; static int f[][]new int[N][N]; static int a[]new int[N]; static int p[]new int[N]; static int size[]new int[N];//表示以i为根结点的子树的节点数量 static int strength[]new int[N];//表示结点i如果剪断与父亲的连线所需要的力气 static int h[]new int[N]; static int e[]new int[N]; static int ne[]new int[N]; static BufferedReader br new BufferedReader(new InputStreamReader(System.in)); static BufferedWriter bwnew BufferedWriter(new OutputStreamWriter(System.out)); public static void main(String[] args) throws IOException { StringTokenizer stnew StringTokenizer(br.readLine()); nInteger.parseInt(st.nextToken()); wInteger.parseInt(st.nextToken()); stnew StringTokenizer(br.readLine()); for (int i 1; i n; i) { a[i]Integer.parseInt(st.nextToken()); } strength[1]Integer.MAX_VALUE;//初始化 for (int i 2; i n; i) { stnew StringTokenizer(br.readLine()); p[i]Integer.parseInt(st.nextToken()); strength[i]Integer.parseInt(st.nextToken()); add(p[i],i); } //定义f[u][j]表示以u为根的所有子树中获取到k个气球的最小代价 不包括对u的操作 for (int i 1; i n; i) { for (int j 1; j n; j) { f[i][j]Integer.MAX_VALUE/2;//防止溢出 } } dfs(1); for (int i n; i 0; i--) { if(f[1][i]w){ bw.write(i); break; } } br.close(); bw.flush(); bw.close(); } static void dfs(int u){ size[u]1; int tmp[]new int[N]; // Arrays.fill(tmp, Integer.MAX_VALUE/2); // tmp[0]0; for (int i h[u]; i 0; ine[i]) { int sone[i]; dfs(son); System.arraycopy(f[u], 0, tmp, 0, N); //合并不同的子树 for (int j 0; j size[u]; j) {//无等号 for (int k 0; k size[son]; k) { if(f[u][j]!Integer.MAX_VALUE/2 f[son][k]!Integer.MAX_VALUE/2)tmp[jk]Math.min(tmp[jk], f[u][j]f[son][k]); } } size[u]size[son]; System.arraycopy(tmp, 0, f[u], 0, N); } f[u][size[u]-1]Math.min(f[u][size[u]-1],a[u]); f[u][size[u]]Math.min(f[u][size[u]], strength[u]); //f[u][size[u]]strength[u];//Math.min(f[u][size[u]], strength[u]); } static void add(int a,int b){ e[id]b; ne[id]h[a]; h[a]id; } }大臣的旅费题目描述很久以前T 王国空前繁荣。为了更好地管理国家王国修建了大量的快速路用于连接首都和王国内的各大城市。为节省经费T 国的大臣们经过思考制定了一套优秀的修建方案使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时如果不重复经过大城市从首都到达每个大城市的方案都是唯一的。J 是 T 国重要大臣他巡查于各大城市之间体察民情。所以从一个城市马不停蹄地到另一个城市成了 J 最常做的事情。他有一个钱袋用于存放往来城市间的路费。聪明的 J 发现如果不在某个城市停下来修整在连续行进过程中他所花的路费与他已走过的距离有关在走第 x 千米到第 xx 1 千米这一千米中 xx 是整数他花费的路费是 xx 10 这么多。也就是说走 1 千米花费 11走 2 千米要花费 23。J 大臣想知道他从某一个城市出发中间不休息到达另一个城市所有可能花费的路费中最多是多少呢输入描述输入的第一行包含一个整数 n表示包括首都在内的 T 王国的城市数。城市从 1 开始依次编号1 号城市为首都。接下来 nn -1 行描述 T 国的高速路 T 国的高速路一定是 nn -1 条。每行三个整数 Pi,Qi,DiPi​,Qi​,Di​表示城市 PiPi​ 和城市 QiQi​ 之间有一条高速路长度为 DiDi​ 千米。输出描述:输出一个整数表示大臣 J 最多花费的路费是多少。输入输出样例示例输入5 1 2 2 1 3 1 2 4 5 2 5 4输出135样例说明大臣 J 从城市 4 到城市 5 要花费 135 的路费。代码1dfsimport java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.*; public class Main { // N 为最大节点数的 5 倍足够存储双向边边数 2*(n-1) static int N 5 * 100010; static int n; static int id 1; // 链式前向星的边编号从 1 开始 // d1[u]从 u 向下走进入子树的最远距离 static int d1[] new int[N]; // p1[u]d1[u] 对应的那条路径经过的第一个子节点 static int p1[] new int[N]; // d2[u]从 u 向下走的次远距离必须与 d1[u] 处于不同分支 static int d2[] new int[N]; // p2[u]d2[u] 对应的路径经过的第一个子节点 static int p2[] new int[N]; // up[u]从 u 向上走朝父节点方向能够到达的最远距离 static int up[] new int[N]; // 链式前向星存图 static int h[] new int[N]; // 邻接表头指针 static int e[] new int[N]; // 边的终点 static int ne[] new int[N]; // 下一条边的编号 static int w[] new int[N]; // 边的长度权值 static BufferedReader br new BufferedReader(new InputStreamReader(System.in)); static BufferedWriter bw new BufferedWriter(new OutputStreamWriter(System.out)); public static void main(String[] args) throws IOException { // 读取城市数量 n StringTokenizer st new StringTokenizer(br.readLine()); n Integer.parseInt(st.nextToken()); // 读取 n-1 条边构建无向树 for (int i 1; i n; i) { st new StringTokenizer(br.readLine()); int a Integer.parseInt(st.nextToken()); int b Integer.parseInt(st.nextToken()); int dis Integer.parseInt(st.nextToken()); add(a, b, dis); add(b, a, dis); } // 第一次 DFS自底向上计算每个节点的 d1, p1, d2, p2 dfs1(1, 0); // 第二次 DFS自顶向下计算每个节点的 up 值 dfs2(1, 0); // 求树的直径最长路径长度 int res Integer.MIN_VALUE; for (int i 1; i n; i) { // 直径可能完全在子树内部以 i 为“最高点” res Math.max(res, d1[i] d2[i]); // 直径可能一端向上、一端向下经过 i res Math.max(res, d1[i] up[i]); } // 根据题目要求计算路费 // 走第 1 千米花费 11第 2 千米花费 12……第 L 千米花费 L10 // 总花费 10*L (12...L) 10*L L*(L1)/2 res (res * (res 1) / 2) 10 * res; bw.write(res ); br.close(); bw.flush(); bw.close(); } /** * 第二次 DFS计算每个节点的 up 值 * up[u] 表示从 u 出发向父节点方向走能到达的最远距离不经过 u 的子树 */ static void dfs2(int u, int p) { for (int i h[u]; i 0; i ne[i]) { int son e[i]; if (son p) continue; // 跳过父节点 // 根据儿子是否在 u 的最长向下路径上决定从 u 向下能用的最优分支 if (son p1[u]) { // 如果 son 就是 d1[u] 经过的那个儿子则从 u 向下只能选次长分支 d2[u] up[son] w[i] Math.max(up[u], d2[u]); } else { // 否则可以选用最长分支 d1[u] up[son] w[i] Math.max(up[u], d1[u]); } // 递归计算子节点 dfs2(son, u); } } /** * 第一次 DFS后序遍历计算每个节点的 d1, p1, d2, p2 * d1[u]向下最远距离 p1[u]对应的第一个子节点 * d2[u]向下次远距离 p2[u]对应的第一个子节点 */ static void dfs1(int u, int p) { for (int i h[u]; i 0; i ne[i]) { int son e[i]; if (son p) continue; // 跳过父节点 dfs1(son, u); // 先递归计算子树 // 当前分支能提供的向下距离 子树的最大向下距离 边权 int d d1[son] w[i]; // 尝试更新最远和次远记录 if (d d1[u]) { // 新的最远距离原最远降为次远 d2[u] d1[u]; p2[u] p1[u]; d1[u] d; p1[u] son; } else if (d d2[u]) { // 只更新次远 d2[u] d; p2[u] son; } } } /** * 链式前向星加边 * param a 起点 * param b 终点 * param dis 边的长度 */ static void add(int a, int b, int dis) { e[id] b; // 边的终点 w[id] dis; // 边的权值 ne[id] h[a]; // 新边指向原来 a 的第一条边 h[a] id; // 头指针指向新边边编号自增 } }代码2bfs在树中从任意一点出发通过 BFS 或 DFS 找到距离它最远的点 u再从 u 出发找到距离 u 最远的点 v那么 u 和 v 之间的路径就是树的直径。第一次找到的最远点一定是直径的一端。import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.*; public class Main { static int N5*10010; static int n; static int id1; static int maxdis[]new int[N]; static int h[]new int[N]; static int e[]new int[N]; static int ne[]new int[N]; static int w[]new int[N]; static BufferedReader br new BufferedReader(new InputStreamReader(System.in)); static BufferedWriter bwnew BufferedWriter(new OutputStreamWriter(System.out)); public static void main(String[] args) throws IOException { StringTokenizer stnew StringTokenizer(br.readLine()); nInteger.parseInt(st.nextToken()); for (int i 1; i n; i) { stnew StringTokenizer(br.readLine()); int aInteger.parseInt(st.nextToken()); int bInteger.parseInt(st.nextToken()); int disInteger.parseInt(st.nextToken()); add(a,b,dis);add(b,a,dis); } int ubfs(1); int resnodebfs(u); bw.write(10*maxdis[resnode]maxdis[resnode]*(1maxdis[resnode])/2); br.close(); bw.flush(); bw.close(); } static int bfs(int u){ QueueInteger queuenew LinkedListInteger(); boolean visited[]new boolean[n1]; int d[]new int[n1]; Arrays.fill(d, Integer.MAX_VALUE); queue.add(u); d[u]0; visited[u]true; int maxnode1,maxnodedis0; while(!queue.isEmpty()){ int gqueue.poll(); for (int i h[g]; i 0; ine[i]) { int sone[i]; if(visited[son])continue; d[son]d[g]w[i]; if(d[son]maxnodedis){ maxnodeson; maxnodedisd[son]; } queue.add(son); visited[son]true; } } for (int i 1; i n; i) { maxdis[i]d[i]; } return maxnode; } static void add(int a,int b,int dis){ e[id]b; w[id]dis; ne[id]h[a]; h[a]id; } }蓝桥舞会题目描述蓝桥公司一共有 nn 名员工编号分别为 1∼n1∼n。他们之间的关系就像一棵以董事长为根的树父节点就是子节点的直接上司。每个员工有一个快乐指数 aiai​。现蓝桥董事会决定举办一场蓝桥舞会来让员工们在工作之余享受美好时光不过对于每个员工他们都不愿意与自己的直接上司一起参会。董事会希望舞会的所有参会员工的快乐指数总和最大请你求出这个最大值。输入描述输入的第一行是一个整数 nn表示蓝桥公司的员工数。第二行包含 nn 个整数分别表示第 ii 个员工的快乐指数 aiai​。接下来 n−1n−1 行每行包含两个整数 u,vu,v表示 vv 是 uu 的直接上司。1≤u,v,ai≤n≤1051≤u,v,ai​≤n≤105​输出描述输出一个整数表示答案。输入输出样例示例 1输入3 1 2 3 2 1 3 1输出5import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.*; public class Main { static int N100010; static int n; static int id1; static int f[][]new int[N][2]; static int a[]new int[N]; static int h[]new int[N]; static int e[]new int[N]; static int ne[]new int[N]; static int w[]new int[N]; static BufferedReader br new BufferedReader(new InputStreamReader(System.in)); static BufferedWriter bwnew BufferedWriter(new OutputStreamWriter(System.out)); public static void main(String[] args) throws IOException { StringTokenizer stnew StringTokenizer(br.readLine()); nInteger.parseInt(st.nextToken()); boolean p[]new boolean[n1]; stnew StringTokenizer(br.readLine()); for (int i 1; i n; i) { a[i]Integer.parseInt(st.nextToken()); } for (int i 1; i n; i) { stnew StringTokenizer(br.readLine()); int uInteger.parseInt(st.nextToken()); int vInteger.parseInt(st.nextToken()); p[u]true; add(v,u); } int root0; for (int i 1; i n; i) { if(p[i]false){ rooti; break; } } //f[u][0]表示在以u为根的子数中如果说u不参加可以获得的最大快乐指数 //f[u][1]表示在以u为根的子数中如果说u参加可以获得的最大快乐指数 dfs(root); bw.write(Math.max(f[root][1], f[root][0])); br.close(); bw.flush(); bw.close(); } static void dfs(int u){ f[u][1]a[u]; for (int i h[u]; i 0; ine[i]) { int je[i]; dfs(j); f[u][0]Math.max(f[j][0],f[j][1]); f[u][1]f[j][0]; } } static void add(int a,int b){ e[id]b; ne[id]h[a]; h[a]id; } }树的连边II问题描述给定 NN 个结点以及 N−1N−1 条边的树你可以选择树中任意两点连成一条边形成一个环对于所有的连接方式请问形成环内包含的结点数次大值可以为多少注这里的次大值为严格意义上的次大值。输入格式第一行输入一个正整数 NN。接下来 N−1N−1 行每行输入 22 个正整数 aa 和 bb代表 aa 结点与 bb 结点有一条无向边。输出格式输出一个整数表示环内包含的次大节点数。样例输入5 1 4 1 5 4 2 4 3样例输出3说明对于样例生成的树如下所示。[1,4,2,5] 与 [1,4,3,5][1,4,3,5] 均是含有 44 个结点的环[2,4,3][2,4,3] 为含有 33 个结点的环因此你需要输出 33。评测数据规模3≤n≤105,1≤a,b≤n3≤n≤105,1≤a,b≤n。代码1bfsimport java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.*; public class Main { static int N2*100010; static int n; static int id1; static int dis[]new int[N]; static int h[]new int[N]; static int e[]new int[N]; static int ne[]new int[N]; static int w[]new int[N]; static BufferedReader br new BufferedReader(new InputStreamReader(System.in)); static BufferedWriter bwnew BufferedWriter(new OutputStreamWriter(System.out)); public static void main(String[] args) throws IOException { StringTokenizer stnew StringTokenizer(br.readLine()); nInteger.parseInt(st.nextToken()); for (int i 1; i n; i) { stnew StringTokenizer(br.readLine()); int aInteger.parseInt(st.nextToken()); int bInteger.parseInt(st.nextToken()); add(a,b);add(b,a); } int ubfs(1); int vbfs(u); bw.write(dis[v]); br.close(); bw.flush(); bw.close(); } static int bfs(int u){ disnew int[N]; QueueInteger queuenew LinkedListInteger(); queue.add(u);dis[u]0; boolean visited[]new boolean[n1]; visited[u]true; while(!queue.isEmpty()){ int gqueue.poll(); for (int i h[g]; i 0; ine[i]) { int sone[i]; if(!visited[son]){ dis[son]dis[g]1; queue.add(son); visited[son]true; } } } int res0,maxdisInteger.MIN_VALUE; for (int i 1; i n; i) { if(maxdisdis[i]){ resi; maxdisdis[i]; } } return res; } static void add(int a,int b){ e[id]b; ne[id]h[a]; h[a]id; } }代码2dfsimport java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.*; public class Main { static int N2*100010; static int n; static int id1; static int d1[]new int[N]; static int d2[]new int[N]; static int s1[]new int[N]; static int s2[]new int[N]; static int up[]new int[N]; static int h[]new int[N]; static int e[]new int[N]; static int ne[]new int[N]; static int w[]new int[N]; static BufferedReader br new BufferedReader(new InputStreamReader(System.in)); static BufferedWriter bwnew BufferedWriter(new OutputStreamWriter(System.out)); public static void main(String[] args) throws IOException { StringTokenizer stnew StringTokenizer(br.readLine()); nInteger.parseInt(st.nextToken()); for (int i 1; i n; i) { stnew StringTokenizer(br.readLine()); int aInteger.parseInt(st.nextToken()); int bInteger.parseInt(st.nextToken()); add(a,b);add(b,a); } dfs1(1,0); dfs2(1,0); int resInteger.MIN_VALUE; for (int i 1; i n; i) { resMath.max(res, d1[i]up[i]); resMath.max(res, d1[i]d2[i]); } bw.write(res); br.close(); bw.flush(); bw.close(); } static void dfs1(int u,int p){ for (int i h[u]; i 0; ine[i]) { int sone[i]; if(sonp)continue; dfs1(son,u); int curd1[son]1; if(curd1[u]){ d2[u]d1[u]; s2[u]s1[u]; d1[u]cur; s1[u]son; }else if(curd2[u]){ d2[u]cur; s2[u]son; } } } static void dfs2(int u,int p){ for (int i h[u]; i 0; ine[i]) { int sone[i]; if(sonp)continue; up[son]1up[u]; dfs2(son, u); } } static void add(int a,int b){ e[id]b; ne[id]h[a]; h[a]id; } }糖果题目描述糖果店的老板一共有 MM 种口味的糖果出售。为了方便描述我们将 MM 种口味编号 1∼ MM。小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果而是 KK 颗一包整包出售。幸好糖果包装上注明了其中 KK 颗糖果的口味所以小明可以在买之前就知道每包内的糖果口味。给定 NN 包糖果请你计算小明最少买几包就可以品尝到所有口味的糖果。输入描述第一行包含三个整数 N,M,KN,M,K。接下来 NN 行每行 KK 个整数 T1,T2,⋅⋅⋅,TKT1​,T2​,⋅⋅⋅,TK​代表一包糖果的口味。其中1≤N≤100,1≤M≤20,1≤K≤20,1≤Ti≤M1≤N≤100,1≤M≤20,1≤K≤20,1≤Ti​≤M。输出描述输出一个整数表示答案。如果小明无法品尝所有口味输出 −1。输入输出样例示例输入6 5 3 1 1 2 1 2 3 1 1 3 2 3 5 5 4 2 5 1 2输出2import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.*; public class Main { static int N(120)1; static int n,m,k; static int id1; static int pack[]new int[N]; static int f[]new int[N]; static int h[]new int[N]; static int e[]new int[N]; static int ne[]new int[N]; static int w[]new int[N]; static BufferedReader br new BufferedReader(new InputStreamReader(System.in)); static BufferedWriter bwnew BufferedWriter(new OutputStreamWriter(System.out)); public static void main(String[] args) throws IOException { StringTokenizer stnew StringTokenizer(br.readLine()); nInteger.parseInt(st.nextToken()); mInteger.parseInt(st.nextToken()); kInteger.parseInt(st.nextToken()); for (int i 1; i n; i) { stnew StringTokenizer(br.readLine()); int state0; for (int j 0; j k; j) { int uInteger.parseInt(st.nextToken()); state|(1(u-1)); } pack[i]state; } Arrays.fill(f, Integer.MAX_VALUE); f[0]0; //定义f[i]为到达状态i时的需要的最小包数 for (int i 1; i n; i) { int curpackpack[i]; for (int j (1m)-1; j 0; j--) {//倒序 int newstate(curpack|j); if(f[j]!Integer.MAX_VALUE)f[newstate]Math.min(f[newstate], f[j]1); } } if(f[(1m)-1]!Integer.MAX_VALUE)bw.write(f[(1m)-1]); else bw.write(-1); br.close(); bw.flush(); bw.close(); } static void add(int a,int b){ e[id]b; ne[id]h[a]; h[a]id; } }