最近acm集训又双叒来了,新学了并查集,来更一贴
先来个模板题!
洛谷 3366 最小生成树
#include
//时间关系注释写的不是很详细。
using namespace std;
int S[100005]; //并查集
struct Edge{
int u,v,w;}edge[100005];//定义边
bool cmp(Edge a,Edge b){
return a.w<b.w;}
int find(int u){
return S[u]==u?u:find(S[u]);}//查询并查集
int m,n,num,k,ans;
int kruskal(){
for(int i=1;i<=n;i++)
S[i]=i;
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=m;i++){
int b=find(edge[i].u);
int c=find(edge[i].v);
if(b==c)continue;
S[b]=c;
num++;
if(ans<edge[i].w)ans=edge[i].w;
}
return ans;
}
int main()
{
while(~scanf("%d %d",&n,&m)){
for(int i=1;i<=m;i++)
scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);
printf("%d\n",kruskal());
}
return 0;
}
在更一道考察联通的问题,话说在离散数学的上机考试也应该会考到相关算法。
洛谷 1536 村村通
话不多说,直接上代码,其实并查集都一个意思,看懂了就都懂了。
#include
//和上一个模板题一样的思路
using namespace std;
int S[1005]; //并查集
struct Edge{
int u,v;}edge[10005];//定义边
int find(int u){
return S[u]==u?u:find(S[u]);}//查询并查集
int m,n,num;
int kruskal(){
int ans=0;
for(int i=1;i<=n;i++)
S[i]=i;
for(int i=1;i<=m;i++){
int b=find(edge[i].u);
int c=find(edge[i].v);
if(b==c)continue;
S[b]=c;
num++;
}
return n-1-num;
}
int main()
{
while(~scanf("%d %d",&n,&m)){
if(n==0)break;
num=0;
for(int i=1;i<=m;i++)
scanf("%d %d",&edge[i].u,&edge[i].v);
printf("%d\n",kruskal());
}
return 0;
}
继续更一道
洛谷 2820 局域网
#include
//还是最开始的模板!hhh
using namespace std;
int S[1000]; //并查集
struct Edge{
int u,v,w;}edge[1005];//定义边
bool cmp(Edge a,Edge b){
return a.w<b.w;}
int find(int u){
return S[u]==u?u:find(S[u]);}//查询并查集
int m,n,sum;
int kruskal(){
int ans=0;
for(int i=1;i<=n;i++)
S[i]=i;
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=m;i++){
int b=find(edge[i].u);
int c=find(edge[i].v);
if(b==c)continue;
S[b]=c;
ans+=edge[i].w;
}
return sum-ans;
}
int main()
{
while(~scanf("%d %d",&n,&m)){
sum=0;
for(int i=1;i<=m;i++){
scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);
sum+=edge[i].w;}
printf("%d\n",kruskal());
}
return 0;
}
以上都是一个模板的,下面更新一道稍难的(虽然官方认定为普及水平),因为要考虑联通分支是否满足,不过想清楚了还是一个并查集!
洛谷 1195 口袋的天空
#include
//稍有不同,但大致思路一样!
using namespace std;
int S[100005]; //并查集
struct Edge{
int u,v,w;}edge[100005];//定义边
bool cmp(Edge a,Edge b){
return a.w<b.w;}
int find(int u){
return S[u]==u?u:find(S[u]);}//查询并查集
int m,n,num,k,ans;
void kruskal(){
for(int i=1;i<=n;i++)
S[i]=i;
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=m;i++){
int b=find(edge[i].u);
int c=find(edge[i].v);
if(b==c)continue;
S[b]=c;
num++;
ans+=edge[i].w;
if(num==n-k)return;
}
return ;
}
int main()
{
while(~scanf("%d %d %d",&n,&m,&k)){
num=0;
for(int i=1;i<=m;i++)
scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);
kruskal();
if(num==n-k)
printf("%d\n",ans);
else printf("No Answer\n");
}
return 0;
}
最后来一道usaco的体验体验
洛谷 1547 [USACO05MAR]Out of Hay S
题目不难,直接上代码!
#include
using namespace std;
int S[100005]; //并查集
struct Edge{
int u,v,w;}edge[100005];//定义边
bool cmp(Edge a,Edge b){
return a.w<b.w;}
int find(int u){
return S[u]==u?u:find(S[u]);}//查询并查集
int m,n,num,k,ans;
int kruskal(){
for(int i=1;i<=n;i++)
S[i]=i;
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=m;i++){
int b=find(edge[i].u);
int c=find(edge[i].v);
if(b==c)continue;
S[b]=c;
num++;
if(ans<edge[i].w)ans=edge[i].w;
}
return ans;
}
int main()
{
while(~scanf("%d %d",&n,&m)){
for(int i=1;i<=m;i++)
scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);
printf("%d\n",kruskal());
}
return 0;
}
今天先更到这,学校oj上还有几题,到时候做完一起来更新!