news 2026/2/6 9:32:45

UVa 1306 The K-League

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
UVa 1306 The K-League

题目描述

K \texttt{K}K联赛(原韩国职业足球联赛)正在进行中,每支球队都有支持者为其助威。在赛季进行到某个阶段后,支持者们想知道他们支持的球队S SS是否还有可能赢得冠军(允许并列冠军)。具体来说,问题是:给定当前每支球队的胜场数w i w_iwi和负场数d i d_idi,以及每对球队之间剩余的比赛场数a i , j a_{i,j}ai,j,能否为剩余的所有比赛分配胜者,使得最终没有球队的总胜场数超过球队S SS的总胜场数?

输入格式

  • 第一行:测试用例数T TT
  • 每个测试用例包含三行:
    1. 球队数n ( 1 ≤ n ≤ 25 ) n(1 \leq n \leq 25)n(1n25)
    2. 2 n 2n2n个非负整数w 1 , d 1 , w 2 , d 2 , … , w n , d n w_1,d_1,w_2,d_2,\ldots,w_n,d_nw1,d1,w2,d2,,wn,dn,每个≤ 100 \leq 100100
    3. n 2 n^2n2个非负整数a 1 , 1 , a 1 , 2 , … , a n , n a_{1,1},a_{1,2},\ldots,a_{n,n}a1,1,a1,2,,an,n,每个≤ 10 \leq 1010,表示剩余比赛场数,保证a i , j = a j , i a_{i,j}=a_{j,i}ai,j=aj,ia i , i = 0 a_{i,i}=0ai,i=0

输出格式
对于每个测试用例,输出一行,按编号递增顺序输出所有可能夺冠的球队编号。

题目分析

这个问题本质上是一个可行性判断问题:对于每支候选球队x xx,判断是否存在一种剩余比赛的胜负分配方案,使得所有球队的最终胜场数都不超过球队x xx的最大可能胜场数。

关键观察

  1. 胜场数上限:对于球队x xx,假设它剩余的所有比赛全胜,那么它的最大可能胜场数为:
    m a x W i n = w x + ∑ j = 1 n a x , j maxWin = w_x + \sum_{j=1}^{n} a_{x,j}maxWin=wx+j=1nax,j

  2. 约束条件:对于其他任何球队i ii,其最终胜场数不能超过m a x W i n maxWinmaxWin,即:
    w i + ( 球队 i 在剩余比赛中获得的胜场数 ) ≤ m a x W i n w_i + (\text{球队$i$在剩余比赛中获得的胜场数}) \leq maxWinwi+(球队i在剩余比赛中获得的胜场数)maxWin
    等价于:
    球队 i 在剩余比赛中最多还能赢 m a x W i n − w i 场 \text{球队$i$在剩余比赛中最多还能赢} \quad maxWin - w_i \quad \text{场}球队i在剩余比赛中最多还能赢maxWinwi

  3. 比赛分配:每场剩余比赛必须在两个参赛队伍之间分配一个胜场。

转化为网络流问题

这是一个典型的多源多汇分配问题,可以转化为最大流问题来判断可行性。

建图方法

对于每个待检查的球队x xx,我们构建这样一个流网络:

  1. 节点类型

    • 源点s o u r c e sourcesource
    • 每场剩余比赛一个节点(如果a i , j > 0 a_{i,j} > 0ai,j>0i < j i < ji<j
    • 每支球队一个节点
    • 汇点s i n k sinksink
  2. 边与容量

    • 从源点到每场比赛节点:容量为该比赛剩余场数a i , j a_{i,j}ai,j
    • 比赛节点到对应的两支球队节点:容量为无穷大(表示这场比赛的胜场可以分配给任意一支参赛队伍)
    • 球队节点到汇点:容量为m a x W i n − w i maxWin - w_imaxWinwi(表示该球队最多还能赢多少场)
  3. 可行性判断
    计算从源点到汇点的最大流。如果最大流等于所有剩余比赛的总场数,说明存在一种分配方案,使得所有球队的胜场数都不超过m a x W i n maxWinmaxWin,即球队x xx可能夺冠。

为什么这样是正确的?
  • 从源点到比赛节点的流量表示这场比赛被"使用"的次数(即需要分配胜负的场次)。
  • 从比赛节点到球队节点的边保证了每场比赛的胜者必须是参赛的两支球队之一。
  • 从球队节点到汇点的容量限制了每支球队最多能增加的胜场数。
  • 如果最大流等于总剩余比赛数,意味着所有比赛都被成功分配,且没有球队超过胜场限制。

算法复杂度

对于每支待检查的球队:

  • 节点数:最多C 25 2 + 25 + 2 ≈ 327 C_{25}^2 + 25 + 2 \approx 327C252+25+2327
  • 边数:约为比赛节点数的3 33
  • 使用 Dinic 算法求最大流:O ( E V ) O(E\sqrt{V})O(EV)O ( V 2 E ) O(V^2E)O(V2E)在实际中表现良好

总复杂度:O ( n ⋅ maxflow ( V , E ) ) O(n \cdot \text{maxflow}(V,E))O(nmaxflow(V,E)),在n ≤ 25 n \leq 25n25的情况下完全可行。

解题思路步骤

  1. 读取输入:处理T TT个测试用例。
  2. 检查每支球队:对于每支球队i ii,调用判断函数canWin(i)
  3. 判断函数实现
    • 计算目标球队的最大可能胜场m a x W i n maxWinmaxWin
    • 快速检查:如果有任何球队当前胜场w j > m a x W i n w_j > maxWinwj>maxWin,直接返回false
    • 构建流网络:
      • 统计所有剩余比赛(a u , v > 0 a_{u,v} > 0au,v>0u < v u < vu<v)。
      • 创建源点、比赛节点、球队节点、汇点。
      • 添加相应边。
    • 计算最大流,判断是否等于总剩余比赛数。
  4. 输出结果:按编号递增顺序输出所有可能夺冠的球队。

代码实现

// The K-League// UVa ID: 1306// Verdict: Accepted// Submission Date: 2025-12-15// UVa Run Time: 0.120s//// 版权所有(C)2025,邱秋。metaphysis # yeah dot net#include<bits/stdc++.h>usingnamespacestd;structEdge{intto,rev;// 目标节点, 反向边在邻接表中的索引intflow,cap;// 当前流量, 容量Edge(intt,intr,intf,intc):to(t),rev(r),flow(f),cap(c){}};constintINF=1e9;// 无穷大常量// Dinic 最大流算法实现structDinic{vector<vector<Edge>>graph;// 邻接表存图vector<int>level,iter;// 分层图中的层级, 当前弧优化intn;// 节点数Dinic(intnodes){n=nodes;graph.resize(nodes);level.resize(nodes);iter.resize(nodes);}// 添加有向边 from->to, 容量为capvoidaddEdge(intfrom,intto,intcap){Edgea(to,graph[to].size(),0,cap);Edgeb(from,graph[from].size(),0,0);// 反向边初始容量为0graph[from].push_back(a);graph[to].push_back(b);}// BFS构建分层图boolbfs(ints,intt){fill(level.begin(),level.end(),-1);queue<int>q;level[s]=0;q.push(s);while(!q.empty()){intcur=q.front();q.pop();for(Edge&e:graph[cur]){if(level[e.to]==-1&&e.flow<e.cap){level[e.to]=level[cur]+1;q.push(e.to);}}}returnlevel[t]!=-1;// 如果汇点可达, 返回true}// DFS寻找增广路intdfs(intcur,intt,intf){if(cur==t)returnf;for(int&i=iter[cur];i<(int)graph[cur].size();++i){Edge&e=graph[cur][i];if(e.flow<e.cap&&level[e.to]==level[cur]+1){intpushed=dfs(e.to,t,min(f,e.cap-e.flow));if(pushed>0){e.flow+=pushed;graph[e.to][e.rev].flow-=pushed;// 更新反向边returnpushed;}}}return0;}// 计算从s到t的最大流intmaxFlow(ints,intt){intflow=0;while(bfs(s,t)){fill(iter.begin(),iter.end(),0);while(intpushed=dfs(s,t,INF)){flow+=pushed;}}returnflow;}};// 判断指定队伍targetTeam是否可能夺冠boolcanWin(inttargetTeam,vector<int>&wins,vector<vector<int>>&remain,intn){// 计算目标队伍的最大可能胜场数(假设剩余比赛全胜)intmaxWin=wins[targetTeam];for(inti=0;i<n;++i){maxWin+=remain[targetTeam][i];}// 快速检查:如果有队伍当前胜场已超过maxWin, 直接返回falsefor(inti=0;i<n;++i){if(wins[i]>maxWin)returnfalse;}// 统计剩余比赛:只考虑i<j的情况, 避免重复intmatchCount=0;vector<pair<int,int>>matches;// 存储比赛双方编号for(inti=0;i<n;++i){for(intj=i+1;j<n;++j){if(remain[i][j]>0){matchCount++;matches.push_back({i,j});}}}// 节点编号分配:// 0 = 源点source// 1 ~ matchCount = 比赛节点// matchCount+1 ~ matchCount+n = 球队节点// matchCount+n+1 = 汇点sinkinttotalNodes=2+matchCount+n;intsource=0;intsink=totalNodes-1;intmatchStart=1;intteamStart=matchStart+matchCount;// 创建Dinic实例Dinicdinic(totalNodes);// 计算总剩余比赛场数inttotalRemainGames=0;// 添加边:源点 -> 比赛节点for(inti=0;i<matchCount;++i){intu=matches[i].first;intv=matches[i].second;intgames=remain[u][v];dinic.addEdge(source,matchStart+i,games);totalRemainGames+=games;// 比赛节点 -> 两支参赛队伍节点(容量为INF,表示可以任意分配)dinic.addEdge(matchStart+i,teamStart+u,INF);dinic.addEdge(matchStart+i,teamStart+v,INF);}// 添加边:球队节点 -> 汇点for(inti=0;i<n;++i){intcap=maxWin-wins[i];// 该队伍最多还能赢几场if(cap<0)returnfalse;// 不应该发生(前面已检查过)dinic.addEdge(teamStart+i,sink,cap);}// 计算最大流intflow=dinic.maxFlow(source,sink);// 如果最大流等于总剩余比赛数,说明所有比赛都能被分配returnflow==totalRemainGames;}intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);// 加速输入输出inttestCases;cin>>testCases;while(testCases--){intn;cin>>n;vector<int>wins(n);vector<int>defeats(n);// 负场数,实际上在解题中用不到// 读取胜场和负场for(inti=0;i<n;++i){cin>>wins[i]>>defeats[i];}// 读取剩余比赛矩阵vector<vector<int>>remain(n,vector<int>(n));for(inti=0;i<n;++i){for(intj=0;j<n;++j){cin>>remain[i][j];}}// 检查每支队伍是否可能夺冠vector<int>result;for(inti=0;i<n;++i){if(canWin(i,wins,remain,n)){result.push_back(i+1);// 队伍编号从1开始}}// 输出结果(按编号递增顺序)for(size_t i=0;i<result.size();++i){if(i>0)cout<<" ";cout<<result[i];}cout<<endl;}return0;}

算法正确性证明

该算法的正确性基于以下事实:

  1. 完备性:如果存在一种分配方案使得球队x xx可能夺冠,那么对应的流网络存在大小为总剩余比赛数的流。

    • 构造方法:按照分配方案,每场比赛的胜场流向对应的球队节点。
  2. 可靠性:如果流网络存在大小为总剩余比赛数的流,那么可以构造出一种分配方案。

    • 从流网络中提取:对于每条从比赛节点到球队节点的边,其流量表示该球队从这场比赛中获得的胜场数。
  3. 容量限制:球队节点到汇点的容量m a x W i n − w i maxWin - w_imaxWinwi保证了没有球队的胜场会超过m a x W i n maxWinmaxWin

时间复杂度分析

对于每个测试用例:

  • n nn支队伍需要检查,每检查一支队伍需要:
    • 构建流网络:O ( n 2 ) O(n^2)O(n2)
    • 运行 Dinic 算法:O ( V 2 E ) O(V^2E)O(V2E)O ( E V ) O(E\sqrt{V})O(EV),其中V ≈ n ( n − 1 ) 2 + n + 2 V \approx \frac{n(n-1)}{2} + n + 2V2n(n1)+n+2E ≈ 3 × n ( n − 1 ) 2 E \approx 3 \times \frac{n(n-1)}{2}E3×2n(n1)

最坏情况下n = 25 n=25n=25V ≈ 327 V \approx 327V327E ≈ 900 E \approx 900E900Dinic \texttt{Dinic}Dinic算法可以快速运行。总复杂度在可接受范围内。

总结

本题展示了如何将一个实际体育竞赛问题转化为经典的最大流模型。关键点在于:

  1. 确定目标球队的最大可能胜场数。
  2. 将比赛分配问题转化为流网络中的流量分配。
  3. 使用Dinic \texttt{Dinic}Dinic等高效最大流算法判断可行性。

这种将实际问题抽象为图论模型的能力在算法竞赛和实际问题解决中都非常重要。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/2 23:54:08

item_get_pro-获得JD商品详情京东API接口

京东商品详情 Pro 接口&#xff08;以下简称 “Pro 接口”&#xff09;是京东开放平台 / 京东联盟提供的高级版商品数据接口&#xff0c;相比基础版接口&#xff0c;可返回更全维度的商品信息&#xff08;如 SKU 级价格、精细化参数、多维度图片 / 视频、营销信息、库存详情等&…

作者头像 李华
网站建设 2026/2/3 0:24:32

国际网络公司如何选择?业务场景才是关键

在当今这个数字化转型的时代&#xff0c;找到一家合适的国际网络公司对于任何想要在全球范围内扩展其业务的企业来说都至关重要。然而&#xff0c;在琳琅满目的选项面前&#xff0c;许多决策者可能会感到迷茫。毕竟&#xff0c;每家公司都有其独特的优势和局限性&#xff0c;而…

作者头像 李华
网站建设 2026/2/4 16:20:18

博客管理系统测试报告

一、项目简介&#xff1a;本项目实现了一个完整博客系统所应具有的大部分功能。基于前后端分离与安全认证特性&#xff0c;实现功能与业务的合理切分。在用户端&#xff0c;实现了博客列表展示、博客详情查看、个人信息管理、博客发布编辑以及博客更新删除等功能。管理端则具备…

作者头像 李华
网站建设 2026/2/3 0:11:52

一步到位!在 K8S 集群中搭建 Prometheus 监控(CentOS 环境)

前言&#xff1a; Prometheus &#xff08;普罗米修斯&#xff09;是一款开源的系统监控与告警工具&#xff0c;最初由 SoundCloud 开发&#xff0c;后捐赠给 Cloud Native Computing Foundation&#xff08;CNCF&#xff09;并成为毕业项目&#xff0c;广泛用于云原生、容器化…

作者头像 李华
网站建设 2026/2/2 23:42:32

Wan2.2-T2V-A14B实现高保真720P视频生成

Wan2.2-T2V-A14B实现高保真720P视频生成 你有没有试过&#xff0c;把一句“穿汉服的少女站在烟雨中的石桥上”输入某个工具&#xff0c;结果出来的画面要么人物脸不对称&#xff0c;要么背景闪烁、布料飘动像纸片&#xff1f;这种体验让人既兴奋又失望——AI能“看懂”文字&…

作者头像 李华
网站建设 2026/2/4 10:21:46

PaddleOCR文字识别部署优化:使用conda环境与本地镜像源

PaddleOCR文字识别部署优化&#xff1a;使用conda环境与本地镜像源 在企业级AI项目落地过程中&#xff0c;一个看似简单却频繁卡住开发进度的环节——环境搭建。尤其是面对PaddleOCR这类依赖庞杂、对中文支持要求高的工具时&#xff0c;开发者常常遭遇“下载慢、安装失败、版本…

作者头像 李华