并查集的一道题目,不知道为何有些博客上说成是最小生成树,也许最小生成树也可以解决这个问题,坎坎坷坷打完了代码,上交就TLE,好菜啊,不过看了看自己的方法复杂度确实够高的。
看了网上的代码,一个很好的想法:反向考虑,,路断变路修,,,同一天的算一个。。一句就解决了我的超时问题,当然对并查集也有一些改变的,,我觉得自己写不出来。。
首先附自己的代码,虽然TLE,但是很好的帮助我理解了这个题目的解法。。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
int pa[100010];
struct Node
{
int a,b,num;
}p[100010];
void init() //初始化 该函数可以根据具体情况保存和初始化需要的内容
{
for(int i=1;i<=n;i++)
{
pa[i]=i;
}
}
int findset(int a) //不带路劲压缩
{
while(pa[a]!=a)
{
a = pa[a];
}
return a;
}
void union_nodes(int a, int b) //集合合并
{
int a1=findset(a);
int b1=findset(b);
if(a1!=b1) //这个判定条件可选,主要是为了防止findset路径压缩的时候出现死循环
{
pa[a1]=b1; //如果存的是有向图,并且做题时集合中元素的顺序很重要,不能忽略,那么这里应该用"pa[a] = b;"
}
}
int main()
{
int maxn,i,j,k,ans,change;
while(~scanf("%d %d",&n,&m))
{
maxn=0,ans=0;
init();
for(i=0;i<m;i++)
{
scanf("%d %d %d",&p[i].a,&p[i].b,&p[i].num);
union_nodes(p[i].a,p[i].b);
maxn=max(maxn,p[i].num);
}
int anss=0;
//printf("%d\n",maxn);
for(i=0;i<=maxn;i++)
{
init();
change=ans;
ans=0;
for(j=0;j<n;j++)
{
p[j].num-=1;
if(p[j].num>0)
union_nodes(p[j].a,p[j].b);
}
for(k=1;k<=n;k++)
{
if(pa[k]==k)
ans++;
}
if(ans>change&&i!=0)
anss++;
}
printf("%d\n",anss);
}
return 0;
}
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;
int pre[100010],a[100010];
struct road
{
int x,y,d;
bool operator <(const road& e)const/设立优先级
{
return d>e.d;
}
}s[100010];
void lol(int n)
{
int i;
for(i=0;i<=n;i++)//i的数量一定要大于等于n,否则wrong
pre[i]=i;
}
int find(int x)//寻根
{
if(x==pre[x])
return pre[x];
return pre[x]=find(pre[x]);
}
bool ok(int x,int y)//连接检测
{
int fx=find(x);
int fy=find(y);
if(fx==fy)
return false;
pre[fy]=fx;
return true;//这里改得好
}
int main()
{
int n,m;
int i;
while(scanf("%d%d",&n,&m)!=EOF)
{
lol(n);
for(i=0;i<m;i++)
scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].d);
sort(s,s+m);//排序
int num=0,day=-1;
for(i=0;i<m;i++)
{
bool bz=ok(s[i].x,s[i].y);
if(bz&&day!=s[i].d)//反向考虑,,路断变路修,,,同一天的算一个。。
{
num++;
day=s[i].d;
}
}
printf("%d\n",num);
}
return 0;
}