https://pintia.cn/problem-sets/994805148990160896/problems/994805156657348608
思路:
- 存储边的信息。
- 遍历屏蔽每个城市后保持连通所需要的花费;
- 输出
注意:
- 如果是已经修好的,花费就为0,这样可以不用去分别处理通/不通的道路
- 如果屏蔽某个城市后为非连通了,那么就说明这个城市是不可或缺的;代码中用“已经连接了的边的数量是否等于n-2”来进行判定(n-1个点最少连通是n-2条边)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 510;
struct EDGE{
int s,d,cost;
};
vector<EDGE> edge;
vector<int> ans;
int n,m,max_effort=1;
int father[maxn];
int findfather(int x){
if(x==father[x]) return x;
int F = findfather(father[x]);
father[x] = F;
return F;
}
int Cal_effort(int index){// 计算屏蔽index点后保持连通需要的花费
for(int i=1;i<=n;i++) father[i] = i;
int effort=0;
int cnt=0;
for(auto it:edge){
if(it.s==index || it.d==index) continue;
int faa = findfather(it.s);
int fab = findfather(it.d);
if(faa!=fab){ // 这里注意,判断是否全部连通的标准是边是否等于n-2
effort += it.cost;
father[faa] = fab;
cnt += 1;
if(cnt == n-2) return effort;
}
}
return 0x3fffff;
}
bool cmp(EDGE a,EDGE b){
return a.cost < b.cost;
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif
cin >> n >> m;
for(int i=0;i<m;i++){ // 录入边,如果是修好的代表花费为0
int s,d,cost,statu;
cin >> s >> d >> cost >> statu;
if(statu==1) edge.push_back({s,d,0});
else edge.push_back({s,d,cost});
}
sort(edge.begin(),edge.end(),cmp);
for(int i=1;i<=n;i++){
int effort = Cal_effort(i); //计算屏蔽这个点之后的最小生成树
if(effort > max_effort){ //更新最大值
max_effort = effort;
ans.clear();
ans.push_back(i);
}else if(effort == max_effort)
ans.push_back(i);
}
if(ans.size()==0) cout << 0 << endl;
else{
int isprint = 0;
sort(ans.begin(),ans.end());
for(auto it:ans)
printf("%s%d",isprint++>0?" ":"", it);
}
return 0;
}