bzoj 3624: [Apio2008]免费道路

本文深入探讨了贪心算法与Kruskal算法在解决特定问题中的应用,通过实例详细阐述了如何使用这两种算法来寻找最优路径,特别是在处理石路与水泥路的选择问题上,提供了清晰的代码实现与解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

1261400-20171022235031568-1668476842.png

solution

正解:贪心+kruskal
分析发现,有一些石路是必须走的,我们首先找出所有这样的石路,方法是把所有的水泥路加进去,然后再加入石路,可以得出至少需要的石路的数量,我们判断这个数量有没有超过K,然后我们再判断是否可以刚好达到K,以上就是无解的情况,我们再加入几条必须的石路后再任意加入到K条,剩下再加入水泥路得出方案.

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=100005;
int n,m,K;
struct node{
   int x,y,z;
}e[N];
struct Ans{
   int x,y,z;
   Ans(){}
   Ans(int _x,int _y,int _z){x=_x;y=_y;z=_z;}
   void pri(){printf("%d %d %d\n",x,y,z);}
}a[N];
int fa[N],sum[N],tot=0;bool d[N];
il int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void solve(bool t,int lim){
   RG int x,y,z;
   for(int i=1;i<=m;i++){
      x=e[i].x;y=e[i].y;z=e[i].z;
      if(z==t && sum[z]<lim){
         if(find(x)==find(y))continue;
         fa[find(y)]=find(x);sum[t]++;
         a[++tot]=Ans(x,y,z);
         if(t==0)d[i]=true;
      }
   }
}
void work()
{
   RG int i;
   scanf("%d%d%d",&n,&m,&K);
   for(i=1;i<=n;i++)fa[i]=i;
   for(i=1;i<=m;i++)
      scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
   solve(1,N);solve(0,N);
   if(sum[0]+sum[1]<n-1 || sum[0]>K){puts("no solution");return ;}
   sum[0]=sum[1]=tot=0;
   for(i=1;i<=n;i++)fa[i]=i;
   for(i=1;i<=m;i++){
      if(!d[i])continue;
      fa[find(e[i].y)]=find(e[i].x);sum[0]++;
      a[++tot]=Ans(e[i].x,e[i].y,e[i].z);
   }
   solve(0,K);
   if(sum[0]!=K){puts("no solution");return ;}
   solve(1,N);
   for(i=1;i<=tot;i++)a[i].pri();
}
 
int main()
{
    work();
    return 0;
}

转载于:https://www.cnblogs.com/Hxymmm/p/7712750.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值