P1394 山上的国度【洛谷算法习题】

📅 2026/7/2 13:43:12 👁️ 阅读次数 📝 编程学习
P1394 山上的国度【洛谷算法习题】

P1394 山上的国度

网页链接

P1394 山上的国度

题目描述

有一个神秘的小国坐落在南方的青山之上,只有当黄昏时,落日耀眼的余晖刺破薄雾的遮拦,有机缘者才可看到小山上面的n nn个美丽的村庄。

传说这个古老的国家里有m mm条枢纽管道,每一条苍老的管道连接着两个村庄,千百年来为村民提供水源的流通。

n nn个村庄里只有一个水库,从有水库的村庄通过这些枢纽管道向其它村庄提供水源。大家都明白水往低处流,所有村庄都能得到水库的供水。

黄小明就是那个有机缘者,同时他也是个偏执狂(把小猫绑在一起的那个变态小明),他迫切的想要知道水库应该在哪一个村庄,你能帮他解决疑惑吗?

输入格式

第一行输入n , m n,mn,mn , m ≤ 300 n,m \leq 300n,m300)。

第二行输入n nn个正整数,第i ii个数表示第i ii个村庄的海拔。之后m mm行每行两个数表示这两个村庄之间有一条道路。(同海拔之间不能相互流水)

输出格式

若存在这样的村庄,输出两行:第一行为Oui, j'ai trouve la solution.,第二行为村庄的编号。

否则,请输出Non

输入输出样例 #1

输入 #1

4 2 1 2 3 4 1 2 3 4

输出 #1

Non

解题思路

本题本质是有向无环图的入度分析,利用“水往低处流”的规则将无向道路转化为单向有向边,通过统计入度为0的节点数量,即可快速判断是否存在能覆盖所有村庄的水库。

核心原理推导:

  1. 水流只能从高海拔流向低海拔,因此每条无向道路对应一条单向有向边:由海拔高的村庄指向海拔低的村庄;同海拔村庄之间无法流通,不产生有效边。
  2. 转化后的图是严格的有向无环图(DAG):路径上海拔严格递减,不可能形成环路。
  3. 合法水库的存在性等价于入度为0的节点数量:
    • 入度为0的节点没有更高的相邻村庄能向它供水,是所在连通分量的局部最高点;
    • 若入度为0的节点多于1个,说明存在多个互不连通的局部高点,互相之间无法供水,不存在能覆盖所有村庄的水库;
    • 若入度为0的节点恰好1个,它就是全局最高点,从该点出发可沿有向边到达所有其他村庄,是唯一合法的水库位置。

算法执行步骤:

  1. 读入村庄数与道路数,记录每个村庄的海拔,同时标记全局海拔最高的村庄编号。
  2. 遍历每条道路,根据两端海拔高低更新入度:低海拔村庄的入度加1;同海拔则不做处理。
  3. 统计所有入度为0的村庄总数。
  4. 若数量为1,输出合法提示与对应村庄编号;否则输出Non

算法时间复杂度为O ( n + m ) O(n+m)O(n+m),完全适配n , m ≤ 300 n,m \le 300n,m300的数据规模。

总结

核心逻辑:将无向道路按海拔高低转化为单向有向边,通过入度为0的节点数量判定是否存在唯一全局最高点,该点即为合法水库位置。
关键操作:海拔比较定向、入度统计、入度零点计数判定。
效率保障:线性遍历即可完成计算,逻辑简洁无冗余,运行效率极高。

代码简要说明

  1. 变量定义a数组存储各村庄海拔,indug数组存储每个村庄的入度,mm记录全局最高海拔,num记录最高海拔对应的村庄编号。
  2. 输入初始化:读入 n 和 m,依次读取每个村庄的海拔,同步更新全局最高海拔与对应村庄编号。
  3. 入度统计:遍历每条道路,比较两端村庄的海拔,给海拔较低的村庄入度加1;海拔相等则跳过,不产生有效边。
  4. 结果判定:统计入度为0的村庄总数。若恰好1个,输出指定语句与最高村庄编号;否则输出Non
  5. 输入优化:关闭同步流加速输入输出,适配常规数据规模。

代码内容

#include<bits/stdc++.h>usingnamespacestd;#defineendl'\n'typedeflonglongll;typedefunsignedlonglongull;typedefvector<vector<ll>>vvt;typedefpair<ll,ll>pll;constll N=1e3+10;constll INF=1e18;constll M=1e6+10;constll mod=1e9+7;ll indug[309],a[309],num=0,maxn=0,n,m,mm;intmain(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);cin>>n>>m;for(ll i=1;i<=n;i++){cin>>a[i];if(mm<a[i])mm=a[i],num=i;}for(ll i=1;i<=m;i++){ll l,r;cin>>l>>r;if(a[l]>a[r])indug[r]++;elseif(a[r]>a[l])indug[l]++;}ll x=0;for(ll i=1;i<=n;i++)if(indug[i]==0)x++;if(x==1)cout<<"Oui, j'ai trouve la solution."<<endl<<num;elsecout<<"Non";return0;}