感觉思路没有问题,为何只能过部分样例?
基本思路是使用优先队列(大根堆)来存储边的信息,并按照边的权值乘积末尾0的数量进行排序。然后,从大到小依次考虑每条边,如果边连接的两个节点的度都大于1,则可以删去该边,并将其权值乘积末尾0的数量累加到最终的答案中。
这段代码的时间复杂度为O(mlogm),其中m为边的数量。
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
using ll=long long;
const int N=1e5+10;
vector<int> G[N];//邻接表存图
ll a[N];//记录每个点的权值
int d[N];//记录每个点的度
struct Edge {
int weight;
int startVertex;
int endVertex;
bool operator<(const Edge& other) const {
return weight < other.weight;
}
};
priority_queue<Edge> q;
int n,m;
int ans;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
d[u]++;
d[v]++;
ll num=a[u]*a[v];
int w=0;
while(num%10==0){
w++;
num/=10;
}
q.push({w,u,v});
}
while(q.size()){
auto t=q.top();
q.pop();
int w=t.weight,s=t.startVertex,e=t.endVertex;
if(d[s]>1&&d[e]>1){
ans+=w;
d[s]--;
d[e]--;
}
}
cout<<ans;
return 0;
}
感谢,评论区“卖冰糖葫芦的大叔”的解惑,对于本题一言以蔽之:求一个连通图的最小生成树,题目要的答案——不过就是所有边权值减去最小生成树的权值罢了,n、m数量级一致,稀疏图,使用克鲁斯卡尔算法即可。判断图的连通可以使用并查集~