QuickLyric:Android歌词自动获取架构深度解析与技术实现指南
2026/6/7 1:00:42
《鹰巢》是一款非线性剧情的动作冒险游戏。玩家需要从简单任务开始,通过完成越来越难的任务,最终挑战最困难的任务。游戏的核心机制如下:
理解规则后,我们可以将问题分解为两个关键步骤:
确定单次流程的最大任务数KKK
在单次游戏中,由于只能选择难度递增的任务,且不能重复,那么能完成的任务序列本质上就是原任务序列的一个严格递增子序列。而第一次玩游戏时能完成的最大任务数KKK,就是整个任务序列的最长严格递增子序列 (LIS\texttt{LIS}LIS)的长度。
注意:这里我们只关心难度值,任务名称仅用于输入输出,不参与计算。
确定最大可重复流程数
知道了KKK,我们需要找出最多能进行多少次“游戏流程”,使得每次流程都完成恰好KKK个任务(一条从难度最低层到最高层的路径),并且所有流程中没有任务被重复使用。
这可以建模为一个图论问题:
d[j] = d[i] + 1),那么我们就建立一条从iii到jjj的有向边。这样就形成了一个有向无环图 (DAG\texttt{DAG}DAG)。对于节点不相交的路径覆盖,可以通过拆点 + 最大流来解决:
计算最终答案
每次流程完成KKK个任务,最多能进行flowflowflow次流程,因此能完成的最大任务总数为K×flowK \times flowK×flow。
为了更直观地理解题目,我们详细分析题目给出的两个样例:
3 Rob_The_Cop 6 A_Petty_Thief 5 Meet_The_Boss 3任务难度序列:[6, 5, 3]
分析:
6 → 5 → 3(难度递减),但玩家可以按照难度递增的顺序玩:先玩难度333,然后玩难度555(5>35 > 35>3),最后玩难度666(6>56 > 56>5)。所以最长严格递增子序列是[3, 5, 6],长度K=3K = 3K=3。3 Meet_The_Boss 3 Rob_The_Cop 6 A_Petty_Thief 5任务难度序列:[3, 6, 5]
分析:
[3, 6]或[3, 5],长度都是222。注意不能玩[3, 6, 5],因为玩完难度666后,难度5<65 < 65<6,违反了规则。所以K=2K = 2K=2。3 → 6和3 → 5Case #1: 3 Case #2: 2关键启示:样例111和样例222包含了相同的三个任务,只是输入顺序不同,导致答案不同。这凸显了任务难度值本身比输入顺序更重要的规则特性。玩家可以跳过中间的任务,只要保证每次新玩的任务都比之前所有玩过的任务都难即可。
// The Eagle's Nest// UVa ID: 10546// Verdict: Accepted// Submission Date: 2025-12-17// UVa Run Time: 0.000s//// 版权所有(C)2025,邱秋。metaphysis # yeah dot net#include<bits/stdc++.h>usingnamespacestd;intmain(){intcaseNumber=1;// 测试用例编号intN;// 任务数量while(cin>>N&&N!=0){// 读取任务,名称和难度vector<pair<string,int>>missions(N);for(inti=0;i<N;i++)cin>>missions[i].first>>missions[i].second;// 提取难度值vector<int>v(N);for(inti=0;i<N;i++)v[i]=missions[i].second;// 第一步:计算最长严格递增子序列(LIS)的长度K,并记录每个任务的层级d[i]vector<int>d(N,1);// d[i]表示以任务i结尾的LIS长度intmaxLen=1;// 即K值for(inti=0;i<N;i++){for(intj=0;j<i;j++){if(v[j]<v[i]&&d[j]+1>d[i]){d[i]=d[j]+1;}}maxLen=max(maxLen,d[i]);}// 第二步:构建网络流图求解最大不相交路径数// 节点编号:0-源点,1~N为任务入点,N+1~2N为任务出点,2N+1为汇点intsource=0,sink=2*N+1;vector<vector<int>>cap(2*N+2,vector<int>(2*N+2,0));// 任务拆点:每个任务入点到出点容量为1,保证每个任务只被用一次for(inti=0;i<N;i++){cap[i+1][i+1+N]=1;}// 源点连接所有第一层任务(d[i]==1)for(inti=0;i<N;i++){if(d[i]==1){cap[source][i+1]=1;}}// 所有最后一层任务(d[i]==K)连接汇点for(inti=0;i<N;i++){if(d[i]==maxLen){cap[i+1+N][sink]=1;}}// 根据层级关系连接任务:如果v[i] < v[j] 且 d[j] == d[i] + 1,则连边for(inti=0;i<N;i++){for(intj=i+1;j<N;j++){if(v[i]<v[j]&&d[j]==d[i]+1){// 从i的出点连接到j的入点cap[i+1+N][j+1]=1;}}}// Dinic 最大流算法autobfs=[&](vector<int>&level)->bool{fill(level.begin(),level.end(),-1);queue<int>q;q.push(source);level[source]=0;while(!q.empty()){intu=q.front();q.pop();for(intv=0;v<=sink;v++){if(level[v]==-1&&cap[u][v]>0){level[v]=level[u]+1;q.push(v);}}}returnlevel[sink]!=-1;};function<int(int,int,vector<int>&)>dfs=[&](intu,intflow,vector<int>&level)->int{if(u==sink)returnflow;for(intv=0;v<=sink;v++){if(level[v]==level[u]+1&&cap[u][v]>0){intpushed=dfs(v,min(flow,cap[u][v]),level);if(pushed>0){cap[u][v]-=pushed;cap[v][u]+=pushed;returnpushed;}}}return0;};intmaxFlow=0;vector<int>level(sink+1);while(bfs(level)){while(intpushed=dfs(source,INT_MAX,level)){maxFlow+=pushed;}}// 第三步:计算最终答案 = K * 最大不相交路径数intresult=maxLen*maxFlow;cout<<"Case #"<<caseNumber++<<": "<<result<<endl;}return0;}