传送们 :题目连接
思路:定位就是一个最小生成数的水题,先跑一遍最小生成树,找出最小的花费,顺便把最小生成树的边记录下来,然后删边,看再跑最小生成树,看是否能得到相同的花费,如果能的话,则是这条边是可替代的,否则则是不可替代的。
有趣的是,排序再结构体里面重载比写cmp函数快的多。写cmp超时,而重载运算符就能过了。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<stack>
#define eps 1e-7
#define INF 0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxe = 5e4+4;
const int maxn = 500+5;
struct edge{
int u,v,cost,id;
bool operator < (const edge &a){
return cost < a.cost;
}
};
edge es[maxe];
edge es1[maxe];
vector<int> vec;
int pre[maxn];
int V,E;
void init(){
for(int i=1;i<=V;i++)pre[i] = i;
}
int find(int x){
return x == pre[x]?x:pre[x] = find(pre[x]);
}
void unit(int x,int y){
int fx = find(x),fy = find(y);
if(fx!=fy){
pre[fx] = fy;
}
}
bool same(int x,int y){
int fx = find(x),fy = find(y);
return fx == fy;
}
int kruskal(bool flag){
init();
int sum = 0;
sort(es,es+E);
for(int i=0;i<E;i++){
edge e = es[i];
if(!same(e.u,e.v)){
unit(e.u,e.v);
sum+=e.cost;
if(flag){
vec.push_back(e.id);
}
}
}
return sum;
}
void init1(){
for(int j=0;j<E;j++){
es[j].u = es1[j].u;
es[j].v = es1[j].v;
es[j].cost = es1[j].cost;
es[j].id = es1[j].id;
}
}
void solve(){
vec.clear();
init1();
int min_tree = kruskal(true);
int ans = 0,sum = 0;
for(int i=0;i<vec.size();i++){
init1();
es[vec[i]].cost = INF;
int tree = kruskal(false);
if(tree != min_tree){
ans++;
sum+=es1[vec[i]].cost;
}
}
printf("%d %d\n",ans,sum);
}
int main()
{
while(~scanf("%d%d",&V,&E)){
for(int i=0;i<E;i++){
int s,t,cost;
scanf("%d %d %d",&s,&t,&cost);
es1[i].u = s;
es1[i].v = t;
es1[i].cost = cost;
es1[i].id = i;
}
solve();
}
return 0;
}