题目链接:https://ac.nowcoder.com/acm/contest/9984/F
题目大意:给你n个人与m件装备,其中每个人都只能对应配一件装备,每件装备也只能配对应一个人。
每件装备可能对应的人有一个或者两个
同时每件装备具有wi点战斗力
问你最大能获得多少战斗力
思路:
感觉有点类似最大生成树
把每件装备的战斗力都当作边值,人的编号当作点
因为是要最大战斗力那么肯定要排序先最大的边进行合并
利用并查集来合并点,再利用辅助数组v[]判断点是否用过
同时要考虑一下自环的情况(就是每件装备只能对应一个人的时候)
如果这个点没用过就把它选上
AC代码:
#include <iostream> #include <algorithm> using namespace std; struct node{ int x,y; int w; }; int fa[100010]; int vis[100010]; int findfa(int x){//并查集找根节点 return fa[x]==x?x:fa[x]=findfa(fa[x]); } bool cmp(node a,node b){//把边排序 return a.w>b.w; } node edge[100010]; void init(){//并查集初始化 for(int i=1;i<=100000;i++)fa[i]=i; } int main() { init(); int n,m; cin>>n>>m; for(int i=0;i<m;i++){ int k; cin>>k; if(k==1){//自环的情况 int x,w; cin>>x>>w; edge[i].x=x; edge[i].y=x; edge[i].w=w; }else{ int x,y,w; cin>>x>>y>>w; edge[i].x=x; edge[i].y=y; edge[i].w=w; } } sort(edge,edge+m,cmp); long long ans=0; for(int i=0;i<m;i++){ int x=findfa(edge[i].x),y=findfa(edge[i].y); if(x!=y&&( !vis[x] || !vis[y])){//如果这两个人有一个人没装备就把装备分配给那个人 ans+=edge[i].w; fa[y]=x; vis[x]=(vis[x] || vis[y]);//如果两个人都没装备那么他的根节点依然是属于没装备的状态,不然就是有装备的状态 }else if(x==y&&!vis[x]){//自环,如果该点没用过直接加边 ans+=edge[i].w; vis[x]=1; } } cout<<ans<<endl; return 0; }