Children’s Queue .

探讨学生按特定条件排队的问题,通过分析与递推公式解决极大数值的计算挑战。

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5660 Accepted Submission(s): 1755

Description
There are many students in PHT School. One day, the headmaster whose name is PigHeader wanted all students stand in a line. He prescribed that girl can not be in single. In other words, either no girl in the queue or more than one girl stands side by side. The case n=4 (n is the number of children) is like
FFFF, FFFM, MFFF, FFMM, MFFM, MMFF, MMMM
Here F stands for a girl and M stands for a boy. The total number of queue satisfied the headmaster’s needs is 7. Can you make a program to find the total number of queue with n children?

Input
There are multiple cases in this problem and ended by the EOF. In each case, there is only one integer n means the number of children (1<=n<=1000)

Output
For each test case, there is only one integer means the number of queue satisfied the headmaster’s needs.

Sample Input
1
2
3

Sample Output
1
2
4

Source

HDU1297

思路如下:

一个长度n的队列可以看成一个n - 1的队列再追加的1个小孩,这个小孩只可能是:

a.男孩,任何n - 1的合法队列追加1个男孩必然是合法的,情况数为f[n - 1];

b.女孩,在前n - 1的以女孩为末尾的队列后追加1位女孩也是合法的,我们可以转化为n - 2的队列中追加2位女孩;

一种情况是在n - 2的合法队列中追加2位女孩,情况数为f[n - 2];

但我们注意到本题的难点,可能前n - 2位以女孩为末尾的不合法队列(即单纯以1位女孩结尾),也可以追加2位女孩成为合法队列,而这种n - 2不合法队列必然是由n - 4合法队列+1男孩+1女孩的结构,即情况数为f[n - 4]。

若感觉本题较难,可先查看文章:[ACM_HDU_2045]LELE的RPG难题,思路与本题类似,但较为简单。

得出递推公式如下:

f[n] = f[n - 1] + f[n - 2] + f[n - 4]

还有需要注意的是本题中可能得出极大的数字,如当n为1000时,结果为:

12748494904808148294446671041721884239818005733501580815621713101333980596197474744336199742452912998225235910891798221541303838395943300189729514282623665199754795574309980870253213466656184865681666106508878970120168283707307150239748782319037

这种超大数完全不是C++提供的数值类型能够储存的,因此我们可以使用二维数组来模拟超大数运算,代码如下:

 

01.#include<stdio.h>   
02.int main(){  
03.    int n;  
04.    int f[1001][101] = {0};  
05.    f[0][1] = 1;  
06.    f[1][1] = 1;  
07.    f[2][1] = 2;  
08.    f[3][1] = 4;  
09.    for(int i = 4; i < 1001; ++i){  
10.        for(int j = 1; j < 101; ++j){  
11.            f[i][j] += f[i - 1][j] + f[i - 2][j] + f[i - 4][j]; //数组的每一位相加   
12.            f[i][j + 1] += f[i][j] / 10000; //超过4位的部分保存至数组下一位中   
13.            f[i][j] %= 10000;   //每位数组只保存其中4位   
14.        }  
15.    }  
16.    while(scanf("%d", &n) != EOF){  
17.        int k = 100;  
18.        while(!f[n][k--]);  //排除前面为空的数组   
19.        printf("%d", f[n][k + 1]);  //输出结果的前四位   
20.        for(; k > 0; --k){  
21.            printf("%04d", f[n][k]);    //输出其余的所有四位数字,若数字小于四位,则前面用0填充   
22.        }  
23.        printf("\n");  
24.    }  
25.    return 0;  
26.} 
using Mds.Customization.CodeRule; using Mds.Master.Entities; using Mds.Master.Operation; using Mds.Master.Repositories; using Mds.Toolkit; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories; namespace Mds.Master { public class MasterOperationService( IOperationRepository operationRepo, IRepository<SubOperationEntity, Guid> subOperationRepo ) : MdsCrudAppService< OperationEntity, OperationGetOutputDto, Dictionary<string, object>, Guid, OperationGetListInput, OperationCreateInput, OperationUpdateInput >(operationRepo), IMasterOperationService { public async override Task<OperationGetOutputDto> CreateAsync(OperationCreateInput input) { if (string.IsNullOrWhiteSpace(input.OperationCode)) { string code = await CodeService.GenCodeAsync(CodeRuleConstant.OperationCodeRule); input.OperationCode = code; } await base.EnsureEntityUniqueAsync(GuidGenerator.Create(), input, "OperationName"); return await base.CreateAsync(input); } public async override Task<OperationGetOutputDto> UpdateAsync(Guid id, OperationUpdateInput input) { if (string.IsNullOrWhiteSpace(input.OperationCode)) { string code = await CodeService.GenCodeAsync(CodeRuleConstant.OperationCodeRule); input.OperationCode = code; } await base.EnsureEntityUniqueAsync(id, input, "OperationName"); return await base.UpdateAsync(id, input); } #region 外键关联代码 protected override void MapToEntity(OperationUpdateInput updateInput, OperationEntity entity) { base.MapToEntity(updateInput, entity); SetIdForGuids(entity); } protected override void SetIdForGuids(OperationEntity entity) { base.SetIdForGuids(entity); // 1. 筛选当前主工序下的所有子工序(同一层级,保持原始顺序) var subOperations = entity.SubOperations .Where(sub => sub.OperationId == entity.Id) .ToList().OrderBy(sub => sub.StepSequence); // 2. 处理子工序(不排序,保留原始顺序和StepSequence) foreach (var subOp in subOperations) { // 原有逻辑:生成子工序ID + 绑定外键(保留) if (subOp.Id == Guid.Empty) EntityHelper.TrySetId(subOp, () => GuidGenerator.Create(), true); subOp.OperationId = entity.Id; // 原有校验:子工序父编码不能等于主工序编码(保留): Todo: 这里需要在用户编辑页面时就处理,而且这里是多级的不是单级,递归的项目不应该显示在用户的选择项中。 if (subOp.SubOperationId == entity.Id) { throw new BusinessException(MdsDomainErrorCodes.OperationCheck); } // 移除了StepSequence的重排逻辑,保留原始值 } // 资源和收费项外键处理(保持不变) foreach (var item in entity.OperationResource) { if (item.Id == Guid.Empty) EntityHelper.TrySetId(item, () => GuidGenerator.Create(), true); item.OperationId = entity.Id; } foreach (var item in entity.OperationChargeItems) { if (item.Id == Guid.Empty) EntityHelper.TrySetId(item, () => GuidGenerator.Create(), true); item.OperationId = entity.Id; } } public async Task<TreeResponseDto<OperationNodeDto>> GetOperationById(OperationGetListInput input) { // 1. 入参校验 if (input.OperationCode.IsNullOrEmpty()) { return new TreeResponseDto<OperationNodeDto> { TotalCount = 0, Items = new() }; } // 2. 筛选主工序(按Code前缀)并分页 var opQry = await operationRepo.GetQueryableAsync(); var mainOpQuery = opQry .Where(op => op.OperationCode.StartsWith(input.OperationCode)) .OrderBy(op => op.OperationCode); var totalMainOpCount = await AsyncExecuter.CountAsync(mainOpQuery); var pagedMainOpIds = await mainOpQuery .Skip(input.SkipCount) .Take(input.MaxResultCount) .Select(op => op.Id) .ToListAsync(); if (!pagedMainOpIds.Any()) { return new TreeResponseDto<OperationNodeDto> { TotalCount = 0, Items = new() }; } // 3. 调用原有树形逻辑 var nestedTrees = await GetNestedTreeAsync(pagedMainOpIds); // 4. 关键:递归拉平嵌套节点,所有节点作为顶级节点 var flatNodes = new List<OperationNodeDto>(); var queue = new Queue<OperationNodeDto>(nestedTrees); // 初始队列放根节点 while (queue.Count > 0) { var current = queue.Dequeue(); // 克隆当前节点,清空children(避免保留嵌套关系) var flatNode = new OperationNodeDto { Id = current.Id, OperationType = current.OperationType, OperationCode = current.OperationCode, OperationName = current.OperationName, Description = current.Description, StandardDuration = current.StandardDuration, IndirectlyHours = current.IndirectlyHours, FixedHours = current.FixedHours, RequiredQc = current.RequiredQc, IsInActive = current.IsInActive, RecordTypeId = current.RecordTypeId, ParentCode = current.ParentCode, // 保留父编码信息 Level = current.Level, StepSequence = current.StepSequence, ParentId = current.ParentId, // 保留父ID信息 Children = new List<OperationNodeDto>() // 强制子节点为空 }; flatNodes.Add(flatNode); // 将子节点入队,继续拉平(递归处理所有层级) foreach (var child in current.Children) { queue.Enqueue(child); } } // 5. 去重(按ID唯一) var uniqueFlatNodes = flatNodes .GroupBy(node => node.Id) .Select(group => group.First()) .ToList(); // 6. 返回拉平后的结果 return new TreeResponseDto<OperationNodeDto> { TotalCount = uniqueFlatNodes.Count, // 总节点数(主+所有子节点) Items = uniqueFlatNodes // 所有节点均为顶级,无嵌套 }; } #endregion #region 查询Operation Tree数据方法 public Task<List<OperationNodeFlatDto>> GetFlatTreeAsync(IEnumerable<Guid> rootIds) => GetFlatNodesAsync(rootIds); public Task<List<OperationNodeFlatDto>> GetFlatTreeAsync(Guid rootId) => GetFlatNodesAsync(new[] { rootId }).ContinueWith(t => t.Result.ToList()); public Task<OperationNodeDto?> GetNestedTreeAsync(Guid rootId) => GetNestedTreeAsync(new[] { rootId }).ContinueWith(t => t.Result.FirstOrDefault()); //#region 修改查询方法(返回前端所需格式) //// 1. 修改 GetAllOperationsTreeAsync 方法的返回类型为 TreeResponseDto<OperationNodeDto> //public async Task<TreeResponseDto<OperationNodeDto>> GetAllOperationsTreeAsync() //{ // var opQry = await operationRepo.GetQueryableAsync(); // var allOperationIds = await opQry // .Select(o => o.Id) // .ToListAsync(); // // 获取原始嵌套树形数据 // var nestedTrees = await GetNestedTreeAsync(allOperationIds); // // 2. 根节点去重(按 Id 唯一,避免同一节点多次作为根节点) // var uniqueRoots = nestedTrees // .GroupBy(node => node.Id) // 按节点唯一标识分组 // .Select(group => group.First()) // 每组只保留第一个节点(去重) // .ToList(); // // 3. 包装为前端所需格式 // return new TreeResponseDto<OperationNodeDto> // { // TotalCount = uniqueRoots.Count, // 总根节点数量(可根据需求改为总节点数) // Items = uniqueRoots // 去重后的嵌套根节点数组 // }; //} //#endregion #region 修改查询方法(返回前端所需格式) // 1. 修改 GetAllOperationsTreeAsync 方法的返回类型为 TreeResponseDto<OperationNodeDto> public async Task<TreeResponseDto<OperationNodeDto>> GetAllOperationsTreeAsync() { var opQry = await operationRepo.GetQueryableAsync(); var allOperationIds = await opQry .Select(o => o.Id) .ToListAsync(); // 获取原始嵌套树形数据 var nestedTrees = await GetNestedTreeAsync(allOperationIds); // 2. 根节点去重(按 Id 唯一,避免同一节点多次作为根节点) var uniqueRoots = nestedTrees .GroupBy(node => node.Id) // 按节点唯一标识分组 .Select(group => group.First()) // 每组只保留第一个节点(去重) .ToList(); // 3. 关键:只保留一级根节点中有子工序的节点(Children 不为空) var filteredRoots = uniqueRoots .Where(root => root.Children != null && root.Children.Any()) .ToList(); // 4. 包装为前端所需格式 return new TreeResponseDto<OperationNodeDto> { TotalCount = filteredRoots.Count, // 过滤后的一级根节点数量 Items = filteredRoots // 仅保留有子工序的一级根节点,其子节点正常保留(无论是否有子工序) }; } #endregion public async Task<List<OperationNodeDto>> GetNestedTreeAsync(IEnumerable<Guid> rootIds) { var flat = await GetFlatNodesAsync(rootIds); if (!flat.Any()) return new(); var roots = new List<OperationNodeDto>(); var nodeById = new Dictionary<Guid, List<OperationNodeDto>>(); // 改成 List! foreach (var item in flat) { var node = new OperationNodeDto { Id = item.Id, OperationType = item.OperationType, OperationCode = item.OperationCode, OperationName = item.OperationName, Description = item.Description, StandardDuration = item.StandardDuration, IndirectlyHours = item.IndirectlyHours, FixedHours = item.FixedHours, RequiredQc = item.RequiredQc, IsInActive = item.IsInActive, RecordTypeId = item.RecordTypeId, ParentCode = item.ParentCode, Level = item.Level, StepSequence = item.StepSequence, ParentId = item.ParentId, Children = new List<OperationNodeDto>() }; // 同一个 Id 可以有多个实例(每条路径一个) if (!nodeById.ContainsKey(item.Id)) nodeById[item.Id] = new List<OperationNodeDto>(); nodeById[item.Id].Add(node); if (item.ParentId == null) { roots.Add(node); } else { // 找到这个父节点的所有实例,子节点挂到所有父实例下(可选) if (nodeById.TryGetValue(item.ParentId.Value, out var parentInstances)) { foreach (var parent in parentInstances) { // 可选:避免重复添加 if (!parent.Children.Any(c => c.Id == node.Id && c.ParentId == item.ParentId)) { parent.Children.Add(node); } } } } } return roots; } #endregion #region 私有方法 private async Task<List<OperationNodeFlatDto>> GetFlatNodesAsync(IEnumerable<Guid> rootIds) { var rootIdList = rootIds?.Where(id => id != Guid.Empty).Distinct().ToHashSet(); if (rootIdList == null || rootIdList.Count == 0) return new(); var opQry = await operationRepo.GetQueryableAsync(); var subOpQry = await subOperationRepo.GetQueryableAsync(); // 1. 收集所有后代 Id var allIds = new HashSet<Guid>(rootIdList); var toProcess = new Queue<Guid>(rootIdList); while (toProcess.Count > 0) { var batch = toProcess.Take(500).ToList(); toProcess = new Queue<Guid>(toProcess.Skip(500)); var childIds = await subOpQry .Where(s => batch.Contains(s.OperationId)) .Select(s => s.SubOperationId) .ToListAsync(); foreach (var childId in childIds) if (allIds.Add(childId)) toProcess.Enqueue(childId); } // 2. 加载所有节点和所有边 var operations = await opQry .Where(o => allIds.Contains(o.Id)) .ToListAsync(); var idToCodeMap = operations.ToDictionary(op => op.Id, op => op.OperationCode); var links = await subOpQry .Where(s => allIds.Contains(s.OperationId) && allIds.Contains(s.SubOperationId)) .OrderBy(s => s.OperationId) .ThenBy(s => s.StepSequence) .ToListAsync(); // 3. 关键:不再用 Dictionary 去重!直接生成多条记录 var result = new List<OperationNodeFlatDto>(); // 用于计算 Level 和路径 var nodeInfo = new Dictionary<Guid, (int Level, Guid? ParentId, int StepSequence)>(); var queue = new Queue<(Guid Id, int Level, Guid? ParentId, int StepSequence)>(); // 初始化根节点 foreach (var rootId in rootIdList) { if (operations.Any(o => o.Id == rootId)) { queue.Enqueue((rootId, 0, null, 0)); nodeInfo[rootId] = (0, null, 0); } } while (queue.Count > 0) { var (currentId, level, parentId, seq) = queue.Dequeue(); var op = operations.First(o => o.Id == currentId); var parentCode = parentId.HasValue ? idToCodeMap.TryGetValue(parentId.Value, out var code) ? code : null : null; // 每出现一次,就生成一条记录(支持多父!) result.Add(new OperationNodeFlatDto { Id = op.Id, OperationType = op.OperationType, OperationCode = op.OperationCode, OperationName = op.OperationName, Description = op.Description, StandardDuration = op.StandardDuration, IndirectlyHours = op.IndirectlyHours, FixedHours = op.FixedHours, RequiredQc = op.RequiredQc, IsInActive = op.IsInActive, RecordTypeId = op.RecordTypeId, ParentCode = parentCode, ParentId = parentId, Level = level, StepSequence = seq }); // 查找当前节点的所有子边 var children = links.Where(l => l.OperationId == currentId).ToList(); foreach (var child in children) { var childId = child.SubOperationId; var childLevel = level + 1; // 即使 childId 已出现过,也要再入队!(支持多路径) queue.Enqueue((childId, childLevel, currentId, child.StepSequence)); } } return result; } #endregion // 在 MasterOperationService 中添加 /// <summary> /// 计算指定工序ID集合的层级(根节点0,子节点=父节点+1) /// </summary> private async Task<Dictionary<Guid, int>> CalculateOperationLevelsAsync(IEnumerable<Guid> operationIds) { var levelMap = new Dictionary<Guid, int>(); if (!operationIds.Any()) return levelMap; // 1. 获取所有相关的父子关系(父OperationId -> 子SubOperationId) var subOpQry = await subOperationRepo.GetQueryableAsync(); var parentChildRelations = await subOpQry .Where(s => operationIds.Contains(s.OperationId) || operationIds.Contains(s.SubOperationId)) .Select(s => new { ParentId = s.OperationId, ChildId = s.SubOperationId }) .ToListAsync(); // 2. 找出所有根节点(没有父节点的工序) var allChildIds = parentChildRelations.Select(r => r.ChildId).ToHashSet(); var rootIds = operationIds.Where(id => !allChildIds.Contains(id)).ToList(); // 3. 初始化根节点层级为0 foreach (var rootId in rootIds) { levelMap[rootId] = 0; } // 4. 递归计算子节点层级(BFS避免栈溢出) var queue = new Queue<Guid>(rootIds); // 从根节点开始遍历 while (queue.Count > 0) { var parentId = queue.Dequeue(); var parentLevel = levelMap[parentId]; // 找出当前父节点的所有子节点 var childIds = parentChildRelations .Where(r => r.ParentId == parentId && operationIds.Contains(r.ChildId)) .Select(r => r.ChildId) .ToList(); foreach (var childId in childIds) { if (!levelMap.ContainsKey(childId)) // 避免重复计算 { levelMap[childId] = parentLevel + 1; // 子节点层级=父节点+1 queue.Enqueue(childId); // 继续计算子节点的子节点 } } } // 5. 处理孤立节点(无任何父子关系,默认层级0) foreach (var id in operationIds) { if (!levelMap.ContainsKey(id)) { levelMap[id] = 0; } } return levelMap; } //public async override Task<PagedResultDto<Dictionary<string, object>>> GetListAsync(OperationGetListInput input) //{ // var opQry = await operationRepo.GetQueryableAsync(); // var allOperationIds = await opQry // .Select(o => o.Id) // .ToListAsync(); // // 获取原始嵌套树形数据 // var nestedTrees = await GetFlatNodesAsync(allOperationIds); // nestedTrees = nestedTrees.Where(n => n.Level > 0).ToList(); // //var entites = ObjectMapper.Map<List<OperationEntity>, List<Dictionary<string, object>>>(nestedTrees); // List<Dictionary<string, object>> entites = new List<Dictionary<string, object>>(); // nestedTrees.ForEach(node => // { // var et = Convert(node); // entites.Add(et); // }); // return new PagedResultDto<Dictionary<string, object>>(entites.Count, entites); //} public async Task<PagedResultDto<OperationGetOutputDto>> GetListTopLevelAsync(OperationGetListInput input) { var opQry = await operationRepo.GetQueryableAsync(); var subOpQry = await subOperationRepo.GetQueryableAsync(); List<Guid> subOpIds = await subOpQry .Select(s => s.SubOperationId) .Distinct() .ToListAsync(); opQry = opQry.Where(o => !subOpIds.Contains(o.Id)); opQry = FilterHelper.CreateFilterQuery(input, opQry); if (!string.IsNullOrWhiteSpace(input.FilterOpt)) { var filterOpt = JObject.Parse(input.FilterOpt); var keywords = filterOpt.ContainsKey("keywords") ? filterOpt["keywords"]?.ToString() : null; if (!string.IsNullOrWhiteSpace(keywords)) { opQry = opQry.Where(o => o.OperationCode.Contains(keywords) || o.OperationName.Contains(keywords));,在这里实现下面代码 public async Task<PagedResultDto<OperationGetOutputDto>> GetListWithFilterAsync(OperationGetListInput input) { // 1. 解析前端传入的FilterOpt JSON字符串 OperationFilterOptions? filter = null; if (!string.IsNullOrWhiteSpace(input.FilterOpt)) { try { var settings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver(), NullValueHandling = NullValueHandling.Ignore }; filter = JsonConvert.DeserializeObject<OperationFilterOptions>(input.FilterOpt, settings); } catch (Exception) { throw new BusinessException("筛选条件格式错误,请传入有效的JSON字符串!"); } } var query = await repository.WithDetailsAsync(); Guid? excludedId = null; if (filter != null && !string.IsNullOrWhiteSpace(filter.Filter_Id)) { string parentIdStr = filter.Filter_Id.Trim(); const string prefix = "opt_"; // 检查是否以 "opt_" 开头 if (parentIdStr.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { // 提取 "opt_" 后面的部分 string suffix = parentIdStr.Substring(prefix.Length).Trim(); // 按空格分割操作符代码和目标值 string[] parts = suffix.Split(new[] { ' ' }, 2); // 尝试解析操作符 if (parts.Length > 0 && Enum.TryParse<OperatorType>(parts[0], out var operatorType)) { // 只有当操作符是 NotEqual 时,才执行排除逻辑 if (operatorType == OperatorType.NotEqual && parts.Length > 1) { // 解析真正的ID值 string idValue = parts[1].Trim(); if (Guid.TryParse(idValue, out Guid parsedId)) { excludedId = parsedId; } } } } } } 但是这个参考代码逻辑 } } var entities = await opQry.ToListAsync(); var dtos = ObjectMapper.Map<List<OperationEntity>, List<OperationGetOutputDto>>(entities); return new PagedResultDto<OperationGetOutputDto>(dtos.Count, dtos); } /// <summary> /// 将对象转换为 Dictionary<string, object>(键为属性名,值为属性值) /// </summary> public static Dictionary<string, object> Convert(OperationNodeFlatDto obj) { if (obj == null) throw new ArgumentNullException(nameof(obj), "对象不能为null"); var dict = new Dictionary<string, object>(); // 获取对象的所有公共实例属性 PropertyInfo[] properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in properties) { // 忽略索引器(如this[]) if (prop.GetIndexParameters().Length > 0) continue; // 获取属性值(支持null值) object value = prop.GetValue(obj); dict[prop.Name] = value; } return dict; } public override async Task<OperationGetOutputDto> GetAsync(Guid id) { var operation = await operationRepo.GetAsync(id); // 计算当前工序的层级 var levelMap = await CalculateOperationLevelsAsync(new[] { id }); var dto = ObjectMapper.Map<OperationEntity, OperationGetOutputDto>(operation); dto.Level = levelMap.TryGetValue(id, out var level) ? level : 0; return dto; } } } excludeid为当前子工序的id,想办法返回operation列表不包含excludeid,子工序为excludeid的主工序要是为别人的子工序,那个别人(主工序)不返回,不要在数据库里递归,最好用上面的方法
最新发布
11-26
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值