P1394 山上的国度
网页链接
P1394 山上的国度
题目描述
有一个神秘的小国坐落在南方的青山之上,只有当黄昏时,落日耀眼的余晖刺破薄雾的遮拦,有机缘者才可看到小山上面的n nn个美丽的村庄。
传说这个古老的国家里有m mm条枢纽管道,每一条苍老的管道连接着两个村庄,千百年来为村民提供水源的流通。
n nn个村庄里只有一个水库,从有水库的村庄通过这些枢纽管道向其它村庄提供水源。大家都明白水往低处流,所有村庄都能得到水库的供水。
黄小明就是那个有机缘者,同时他也是个偏执狂(把小猫绑在一起的那个变态小明),他迫切的想要知道水库应该在哪一个村庄,你能帮他解决疑惑吗?
输入格式
第一行输入n , m n,mn,m(n , m ≤ 300 n,m \leq 300n,m≤300)。
第二行输入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的节点数量,即可快速判断是否存在能覆盖所有村庄的水库。
核心原理推导:
- 水流只能从高海拔流向低海拔,因此每条无向道路对应一条单向有向边:由海拔高的村庄指向海拔低的村庄;同海拔村庄之间无法流通,不产生有效边。
- 转化后的图是严格的有向无环图(DAG):路径上海拔严格递减,不可能形成环路。
- 合法水库的存在性等价于入度为0的节点数量:
- 入度为0的节点没有更高的相邻村庄能向它供水,是所在连通分量的局部最高点;
- 若入度为0的节点多于1个,说明存在多个互不连通的局部高点,互相之间无法供水,不存在能覆盖所有村庄的水库;
- 若入度为0的节点恰好1个,它就是全局最高点,从该点出发可沿有向边到达所有其他村庄,是唯一合法的水库位置。
算法执行步骤:
- 读入村庄数与道路数,记录每个村庄的海拔,同时标记全局海拔最高的村庄编号。
- 遍历每条道路,根据两端海拔高低更新入度:低海拔村庄的入度加1;同海拔则不做处理。
- 统计所有入度为0的村庄总数。
- 若数量为1,输出合法提示与对应村庄编号;否则输出
Non。
算法时间复杂度为O ( n + m ) O(n+m)O(n+m),完全适配n , m ≤ 300 n,m \le 300n,m≤300的数据规模。
总结
核心逻辑:将无向道路按海拔高低转化为单向有向边,通过入度为0的节点数量判定是否存在唯一全局最高点,该点即为合法水库位置。
关键操作:海拔比较定向、入度统计、入度零点计数判定。
效率保障:线性遍历即可完成计算,逻辑简洁无冗余,运行效率极高。
代码简要说明
- 变量定义:
a数组存储各村庄海拔,indug数组存储每个村庄的入度,mm记录全局最高海拔,num记录最高海拔对应的村庄编号。 - 输入初始化:读入 n 和 m,依次读取每个村庄的海拔,同步更新全局最高海拔与对应村庄编号。
- 入度统计:遍历每条道路,比较两端村庄的海拔,给海拔较低的村庄入度加1;海拔相等则跳过,不产生有效边。
- 结果判定:统计入度为0的村庄总数。若恰好1个,输出指定语句与最高村庄编号;否则输出
Non。 - 输入优化:关闭同步流加速输入输出,适配常规数据规模。
代码内容
#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;}