题目链接: http://acm.sdtbu.edu.cn/vjudge/contest/view.action?cid=2195#problem/F
题意大概:找到构成最小生成树的边中不可替代的边
思路: 先跑一边最短路算法(推荐Kruskal,方便对边进行操作,刚开始想用Prim,不过没有写出来,不知道可不可以用Prim做),然后把最小生成树中的边进行标记(我放到了一个队列中,刚开始用flag数组进行标记,时间超限了),然后逐一删除标记的边,每次注意是每次只删一条边,然后跑一边Kruskal,计算最小生成树的权值和,与最初的进行比较,如果不同的话,就说明这条边是不可以删除的,然后记下就可以了。
//struct A
//{
// ll x,y;
// bool operator < (const A & a) const
// {
// return x>a.x;
// }
//};
//priority_queue <A> q;
#include <bits/stdc++.h>
#define eps 0.0000000001
#define mem(a) memset(a,0,sizeof(a))
#define maxx 1e10
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
//priority_queue<ll,vector<ll>,greater<ll> > q;
#define mod 123456789
const ll maxn=50500;
int n,m,ans,sum;
struct A
{
int st,ed;
int w;
} a[maxn];
int father[maxn];
bool flag;
queue<int> q;
bool cmp(A a,A b)
{
return a.w<b.w;
}
int Find(int x)
{
if(x!=father[x])
{
father[x]=Find(father[x]);
}
return father[x];
}
void Union(int x,int y,int n)
{
int fx=Find(x);
int fy=Find(y);
if(fx!=fy)
{
father[fx]=fy;
ans+=a[n].w;
if(flag==0)
{
q.push(n);
}
}
}
void init()
{
ans=0;
for(int i=1; i<=m; i++)
father[i]=i;
return;
}
int main()
{
while(cin>>n>>m)
{
init();flag=0;
int ans_num=0,ans_sum=0;
int x,y,z;
int gg;
for(int i=1; i<=m; i++)
{
cin>>x>>y>>z;
a[i].st=x;
a[i].ed=y;
a[i].w=z;
}
sort(a+1,a+m+1,cmp);
for(int i=1; i<=m; i++)
{
Union(a[i].st,a[i].ed,i);
}
gg=ans;flag=1;
while(!q.empty())
{
int i=q.front();
q.pop();
init();
for(int j=1; j<=m; j++)
{
if(j==i)
continue;
Union(a[j].st,a[j].ed,j);
}
if(ans!=gg)
{
ans_num++;
ans_sum+=a[i].w;
}
}
cout<<ans_num<<" "<<ans_sum<<endl;
}
return 0;
}