Children’s Game - UVa 10905 拼接最大数

本文介绍了一种针对儿童设计的数字游戏,通过给定的多个正整数,寻找由这些整数组合而成的最大可能数值。文章提供了一种排序算法思路,并附带了完整的AC代码实现。

4th IIUC Inter-University Programming Contest, 2005

A

Children’s Game

Input: standard input
Output: standard output

Problemsetter: Md. Kamruzzaman

There are lots of number games for children. These games are pretty easy to play but not so easy to make. We will discuss about an interesting game here. Each player will be given N positive integer. (S)He can make a big integer by appending those integers after one another. Such as if there are 4 integers as 123, 124, 56, 90 then the following integers can be made – 1231245690, 1241235690, 5612312490, 9012312456, 9056124123 etc. In fact 24 such integers can be made. But one thing is sure that 9056124123 is the largest possible integer which can be made.

You may think that it’s very easy to find out the answer but will it be easy for a child who has just got the idea of number?

Input

Each input starts with a positive integer N (≤ 50). In next lines there are N positive integers. Input is terminated by N = 0, which should not be processed.

Output

For each input set, you have to print the largest possible integer which can be made by appending all the Nintegers.

Sample Input

Output for Sample Input

4
123 124 56 90
5
123 124 56 90 9
5
9 9 9 9 9
0

9056124123
99056124123
99999


题意:给你n个数,问你用其拼接的最大的数是多少。

思路:用s1+s2>s2+s1的比较方式来排序,然后按序输出。

AC代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
using namespace std;
string s[60];
bool cmp(string s1,string s2)
{
    return s1+s2>s2+s1;
}
int main()
{
    int n,i,j,k;
    while(~scanf("%d",&n) && n>0)
    {
        for(i=1;i<=n;i++)
           cin>>s[i];
        sort(s+1,s+1+n,cmp);
        for(i=1;i<=n;i++)
           cout<<s[i];
        printf("\n");
    }
}



<think>根据用户需求,需要在Ant Design Vue的a-tree组件中实现单选功能,并拼接每一层节点的name属性形成完整的路径名称。 关键点: 1. 单选功能:即每次只能选中一个节点,且选中一个节点时自动取消其他节点的选中。 2. 拼接路径:需要从当前选中的节点开始,向上回溯直到根节点,将每一层的name属性拼接起来,形成完整的路径。 实现思路: - 使用`checkStrictly`属性来取消父子节点的关联选中(这样可以独立选择每个节点,但注意用户要求是单选,所以即使取消关联,我们也要控制只能选一个)。 - 通过`v-model`绑定选中的节点(注意:这里我们可能需要使用checkedKeys来绑定选中的key,但单选只需要一个key,所以我们可以用数组,但只保留一个元素)。 - 监听选中事件(@check),在事件中处理单选逻辑:将当前选中的节点设置为唯一选中的节点,并取消其他节点的选中状态。 - 同时,在选中事件中,根据选中的节点key,从树的数据结构中向上回溯,拼接name。 步骤: 1. 设置`checkStrictly`为true,这样可以选择任意节点而不影响父节点和子节点。 2. 绑定选中的key数组(因为a-tree的checkedKeys是数组形式,即使单选我们也要用数组,但只包含一个元素)。 3. 在@check事件处理函数中: - 获取当前选中的节点key(可能是选中也可能是取消选中,所以需要判断) - 如果是选中,则把数组设置为只包含当前选中的key(即取消其他所有节点的选中) - 如果是取消选中,则把数组清空(或者根据需求,如果点击已选中的节点则取消选中,此时数组为空) 4. 根据当前选中的key,在树数据中查找该节点,然后向上回溯直到根节点,拼接name。 注意:树数据可能是平铺结构(通过parentId关联)或者嵌套结构(children)。这里假设用户使用的是嵌套结构(tree-data属性传入的是嵌套结构)。 如何向上回溯? 在嵌套结构中,我们可以通过递归遍历树来找到该节点,并记录从根到该节点的路径。但递归遍历效率可能不高,我们可以考虑在构建树时给每个节点添加一个parent引用(非必须,但方便回溯),或者使用一个映射(id到节点)和父节点id来向上回溯。 由于a-tree组件的数据结构是嵌套的,我们可以通过递归函数来查找节点并记录路径。 实现步骤: 1. 定义checkedKeys的响应式数据(使用ref或reactive)。 2. 定义树数据(exampleTreeData)。 3. 在@check事件处理函数中: - 获取当前选中的节点key(事件回调的第一个参数是当前选中的keys数组,第二个参数是事件对象,包含当前操作节点的信息) - 但是注意:@check事件触发时,checkedKeys还没有更新,所以我们可以根据事件对象中的节点信息来确定当前操作的节点。 然而,由于我们设置了checkStrictly,所以每次点击复选框都会触发check事件。我们需要判断当前操作是选中还是取消: - 如果当前节点的key已经在checkedKeys数组中,那么这次操作就是取消选中;否则就是选中。 但是,因为我们要实现单选,所以当选中一个新节点时,我们会将checkedKeys设置为只包含这个新节点的key。因此,在事件处理函数中: - 如果当前节点之前没有被选中(即不在checkedKeys数组中),那么我们就将checkedKeys设置为[当前节点key]。 - 如果当前节点已经被选中(即在checkedKeys数组中),那么我们就将checkedKeys设置为空数组(即取消选中)。 同时,我们需要一个方法来根据当前选中的节点key获取路径名称。 查找节点路径的函数: function findNodePath(tree, key, path = []) { for (let node of tree) { // 如果当前节点就是目标节点,则把当前节点的name加入路径并返回 if (node.key === key) { return path.concat(node.name); } // 如果有子节点,递归查找 if (node.children) { let result = findNodePath(node.children, key, path.concat(node.name)); if (result) { return result; } } } return null; } 然后,在事件处理函数中,我们调用这个函数,得到路径数组,然后用连接符(如'/')拼接起来。 但是注意:我们可能希望从根节点到当前节点的顺序,所以路径数组已经是按顺序的,直接拼接即可。 另外,我们也可以考虑在构建树的时候给每个节点添加parent引用,这样回溯更快。但这里为了简单,使用递归查找。 性能考虑:如果树很大,递归查找可能会有性能问题,但一般树节点数量有限,可以接受。如果节点很多,建议使用映射表(如id->node)和存储父节点key的方式。 另一种方案:在数据加载时,构建一个节点映射(key到节点对象)和每个节点的父节点指针。这样可以通过映射快速找到节点,然后通过父节点指针回溯。 这里我们采用递归查找的方式,因为用户没有提到树很大。 代码结构: 模板部分: <a-tree checkable :tree-data="treeData" :checkStrictly="true" v-model:checkedKeys="checkedKeys" @check="onCheck" /> 脚本部分(使用Vue3 Composition API): import { ref } from 'vue'; const checkedKeys = ref([]); // 当前选中的节点key数组(单选,所以最多一个元素) const selectedPath = ref(''); // 当前选中的路径字符串 const onCheck = (checkedKeys, { node }) => { // 注意:第一个参数是当前选中的keys数组(所有被选中的节点,因为checkStrictly=true,所以可以独立选中多个,但我们只允许一个) // 但是,我们通过控制checkedKeys的值来实现单选,所以不能直接使用这个数组。 // 我们通过node对象来判断当前操作的是哪个节点,以及是选中还是取消。 // node.checked 表示当前操作后该节点的选中状态(但注意,由于我们还没有更新checkedKeys,所以这里node.checked是操作后的状态?实际上,事件触发是在内部状态更新之后,所以node.checked是操作后的状态) // 判断当前节点在操作后是否被选中 if (node.checked) { // 当前节点被选中,那么我们要取消其他节点的选中,即设置checkedKeys为当前节点的key checkedKeys.value = [node.eventKey]; // 注意:在a-tree中,节点对象通常用key属性,但这里事件参数中的node可能是TreeNode对象,具体要看Ant Design Vue的文档。在Ant Design Vue中,节点对象通常有key属性,而eventKey是旧版,新版推荐使用key。但根据文档,节点对象中通常有key。 // 然后,根据这个key去查找路径 const path = findNodePath(treeData.value, node.key); if (path) { selectedPath.value = path.join('/'); } else { selectedPath.value = ''; } } else { // 当前节点被取消选中 checkedKeys.value = []; // 清空选中 selectedPath.value = ''; } }; 但是,注意:在onCheck事件中,我们修改了checkedKeys,这会导致v-model绑定的checkedKeys更新,然后视图更新。但是,这样直接修改可能会导致循环触发?所以我们需要确保不会无限循环。 另外,我们发现事件参数中的checkedKeys(第一个参数)是当前所有被选中的keys(包括之前选中的和这次操作变化的),但我们并不需要它,因为我们通过node.checked知道当前节点的状态,并且我们只允许一个节点被选中。 然而,由于我们设置了checkStrictly=true,所以可以独立选择节点。但是,如果我们只允许一个节点被选中,那么我们就应该忽略其他节点的选中状态,只保留当前操作的节点(如果是选中)或者清空(如果是取消)。 但是,这里有一个问题:当我们设置checkedKeys.value = [node.key]时,会触发@check事件吗?因为v-model绑定的checkedKeys变化了,会触发a-tree内部更新选中状态,然后又会触发@check事件?这样就会导致两次事件。 为了避免循环,我们需要在onCheck中判断:如果当前checkedKeys的值已经是我们想要的值(比如,当前选中的节点只有一个且是我们刚刚设置的),那么就不需要再处理。但是,由于我们是在事件中修改,所以可能会再次触发。 因此,我们可以考虑使用一个标志位来避免递归触发,或者使用另一种方式:不使用v-model绑定,而是使用受控模式(即通过checkedKeys属性控制,然后通过事件更新)。 实际上,我们已经在使用受控模式:因为checkedKeys是响应式数据,通过v-model绑定,然后我们在事件中修改它,然后重新渲染。这样会导致事件再次触发吗? 根据Ant Design Vue的文档,@check事件是在用户点击复选框时触发的,而当我们以编程方式设置checkedKeys时,不会触发@check事件。所以我们可以安全地在@check事件中修改checkedKeys。 但是,为了保险起见,我们可以测试一下,或者查阅文档。不过根据经验,通常不会触发。 因此,我们按照上述思路实现。 另外,关于查找路径的函数findNodePath,我们实现如下: function findNodePath(tree, key, path = []) { for (let i = 0; i < tree.length; i++) { const node = tree[i]; // 当前节点加入路径(注意,这里我们只是记录路径上的节点name,但当前节点是否就是目标节点还不确定,所以先加入?不,我们应该在找到的时候才加入) // 修改:在遍历子节点时,将当前节点的name加入路径,然后传递给子节点。如果当前节点就是目标,则加入当前节点name并返回。 if (node.key === key) { // 注意:path是到父节点的路径,不包括当前节点 return [...path, node.name]; // 返回当前路径加上当前节点的name } if (node.children) { const result = findNodePath(node.children, key, [...path, node.name]); // 将当前节点的name加入路径,传递给子节点 if (result) { return result; } } } return null; } 注意:这个函数中,path参数表示从根节点到当前树(tree)的父节点路径。在递归时,我们将当前节点的name加入路径,然后传递给子节点。当找到目标节点时,目标节点的name也会加入,然后返回。 这样,返回的路径数组就是从根节点到目标节点的所有name。 示例树结构: const treeData = [ { key: '1', name: '一级节点', children: [ { key: '1-1', name: '二级节点1' }, { key: '1-2', name: '二级节点2' } ] } ]; 当key为'1-1'时,返回的路径数组为['一级节点', '二级节点1'],然后拼接成'一级节点/二级节点1'。 最后,将selectedPath显示在页面上即可。 但是,注意:如果树数据很大,递归查找可能比较慢,可以考虑使用映射表。我们可以预先遍历树,构建一个key到节点的映射,以及存储每个节点的父节点引用。然后向上回溯。 这里为了简单,先使用递归查找。 另外,用户可能需要的是从根节点到当前节点的完整路径,包括所有层级。 完整代码示例(Vue3): 注意:在Ant Design Vue中,节点对象有key属性,我们使用key作为唯一标识。 但是,在事件参数中,节点对象可能不是原始数据节点,而是经过封装的TreeNode。根据文档,@check事件的第二个参数是{node, event},其中node是TreeNode对象,我们可以通过node.dataRef获取原始节点数据,或者使用node.key(如果原始节点数据中有key)和node.title(如果原始节点数据中有title)?但是我们的树数据中用的是name,而TreeNode的title属性默认是显示的内容,所以我们需要在树数据中提供title属性,或者使用插槽自定义。但是,为了简单,我们可以在树数据中同时提供name和title,或者将name赋值给title。 在树数据中,我们可以这样: treeData.value = [ { key: '1', title: '一级节点', name: '一级节点', children: [...] } ] 这样,在node.title中就可以拿到,但是路径拼接我们需要的是name(如果name和title相同,那么可以直接用title)。不过,为了通用,我们还是使用name属性。 在TreeNode对象中,我们可以通过node.key获取key,通过node.name可能不行,因为TreeNode没有name属性。所以,我们需要从原始数据中获取name。我们可以通过node.dataRef.name来获取原始数据的name属性(根据Ant Design Vue的文档,TreeNode有一个dataRef属性,指向原始节点数据)。 因此,在onCheck事件中,我们可以这样: const rawNode = node.dataRef; const name = rawNode.name; 但是,在查找路径时,我们使用的是整个树数据,所以查找函数中可以直接使用原始树数据(每个节点有name和key)。 所以,在onCheck事件中,我们可以直接使用node.key来查找树数据,而不需要node.dataRef.name,因为查找函数会从树数据中找到节点并获取name。 因此,我们不需要在事件中获取name,只需要key。 但是,在查找函数中,我们使用的是树数据(treeData.value),所以确保树数据是完整的。 综上所述,我们实现如下: 1. 在模板中,使用a-tree组件,并绑定checkedKeys和check事件。 2. 定义checkedKeys和selectedPath响应式变量。 3. 实现onCheck方法。 4. 实现findNodePath方法。 注意:如果树数据是异步加载的,那么查找路径时可能当前节点还没有加载?所以需要确保树数据已经包含选中的节点。 下面是一个完整的代码示例(Vue3 Composition API):</think>要在 Ant Design Vue 的 `<a-tree>` 组件中实现单选功能并拼接每层节点的 name 属性形成完整路径,可通过以下步骤实现: ### 解决方案代码 ```vue <template> <a-tree checkable :tree-data="treeData" :replaceFields="{ title: 'name' }" :checkedKeys="checkedKeys" :checkStrictly="true" @check="handleCheck" /> <div v-if="selectedPath">当前路径: {{ selectedPath }}</div> </template> <script> import { ref } from 'vue'; export default { setup() { const checkedKeys = ref([]); const selectedPath = ref(''); // 树结构数据示例 const treeData = ref([ { key: '1', name: '根节点', children: [ { key: '1-1', name: '子节点1' }, { key: '1-2', name: '子节点2' }, ], }, { key: '2', name: '二级节点', children: [ { key: '2-1', name: '子节点A' }, { key: '2-2', name: '子节点B' }, ], }, ]); // 递归查找节点路径 const findPath = (nodes, key, path = []) => { for (const node of nodes) { const newPath = [...path, node.name]; if (node.key === key) return newPath; if (node.children) { const result = findPath(node.children, key, newPath); if (result) return result; } } return null; }; // 处理选中事件 const handleCheck = (checkedKeysArr, { node }) => { // 实现单选逻辑 if (checkedKeysArr.length > 0) { checkedKeys.value = [node.key]; } else { checkedKeys.value = []; selectedPath.value = ''; return; } // 拼接路径 const path = findPath(treeData.value, node.key); if (path) { selectedPath.value = path.join(' / '); } }; return { treeData, checkedKeys, selectedPath, handleCheck }; }, }; </script> ``` ### 关键配置说明 1. **单选控制** - `checkStrictly="true"`:解耦父子节点选中状态[^2] - `checkedKeys` 绑定数组,仅存储最后选中的节点 key - 在 `@check` 事件中重置数组为当前节点 key 2. **路径拼接** - 递归函数 `findPath` 从根节点开始查找 - 逐级收集 `name` 属性形成路径数组 - 使用 `join(' / ')` 拼接成字符串(可自定义分隔符) 3. **数据映射** - `:replaceFields="{ title: 'name' }"` 将节点 name 映射为显示文本 ### 效果说明 - ✅ **单选**:点击新节点自动取消旧选项 - ✅ **路径显示**:如选中 "子节点A" 显示:`二级节点 / 子节点A` - ✅ **动态更新**:切换节点时路径实时更新 - ✅ **取消选中**:点击已选节点可清空选择 ### 注意事项 1. 树数据需包含 `key` 和 `name` 字段 2. 异步加载数据时需确保节点加载完成再操作 3. 复杂树结构建议使用 `key` 索引优化查找性能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值