题意:破坏石油管道,现一直破坏各个管道所要付出的代价,问在有一定money并且要保证剩余的管道为生成树的情况下, 最多能破坏多少个管道,并将他们的编号从小到大输出来
思路:将边从大到小排序,构造生成树。 接下来最后剩余的不在最大生成树的边,从最小开始在满足条件下依次取即可。
这里注意: 答案不唯一,输出其中之一即可。
#include <iostream> #include <algorithm> #include <string.h> #include <stdio.h> #include <string> #include <queue> using namespace std; int n,m; int blank=0; long long s; int a,b,cost; int ans[105000]; //若flag为true,则表明该边在生成树里。 //no表示该边的序号 struct Edge{ int u,v; int cost; bool flag; int no; bool operator <(const Edge& temp) const { return temp.cost<cost; } }edge[105000]; struct UF{ int father[55000]; void init(){ for(int i=1;i<=n;i++){ father[i]=i; } } int find_root(int x){ if(father[x]!=x) father[x]=find_root(father[x]); return father[x]; } void Union(int fa,int fb){ father[fb]=fa; } }uf; int main() { while(scanf("%d%d%lld",&n,&m,&s)!=EOF){ if(blank) puts(""); else blank=1; for(int i=0;i<m;i++){ scanf("%d%d%d",&a,&b,&cost); edge[i].u=a; edge[i].v=b; edge[i].cost=cost; edge[i].no=i+1; edge[i].flag=false; } sort(edge,edge+m); int counts=0; uf.init(); for(int i=0;i<m;i++){ int u=edge[i].u; int v=edge[i].v; int fu=uf.find_root(u); int fv=uf.find_root(v); if(counts>=n-1) break; if(fu!=fv){ edge[i].flag=true; uf.Union(fu,fv); counts++; } } int num=0; //从最小边权开始 for(int i=m-1;i>=0;i--){ if(!edge[i].flag){ if(s>=edge[i].cost){ s-=edge[i].cost; ans[num]=edge[i].no; num++; } else{ break; } } } printf("%d\n",num); for(int p=0;p<num;p++){ //如果直接按照"%d "格式输出,也会AC if(p==0) printf("%d",ans[p]); else printf(" %d",ans[p]); } printf("\n"); } return 0; }