一个图,边分为黑边和白边,白边最多能选择k条,并且要保持图连通的情况下,求一个权值和最大的子图
首先贪心的想的话,肯定是要把黑边全选上(因为边权无负值),选完所有黑边之后并查集缩点(一直不知道这个操作叫缩点天啊,我是憨憨),然后缩完的图,用白边跑一次最大生成树,
如果k还有剩余,再把刚才没选的白边也加上。一点点就是多样例输入记得清空,莫名其妙(智商掉线)W了几发。。。
struct IN { ll u,v,w; IN (ll uu,ll vv,ll ww):u(uu),v(vv),w(ww){} bool operator < (IN b) { return w>b.w; } }; ll fa[MAXN]; ll find(ll x) { return x==fa[x]?x:fa[x]=find(fa[x]); } int main() { fast; int t;cin>>t; while(t--) { ll n,m,k; cin>>n>>m>>k; vector<IN>ed0,ed1,ed2; rep(i,m) { int x,y,w,c;cin>>x>>y>>w>>c; if(c==0) ed0.push_back(IN(x,y,w)); else ed1.push_back(IN(x,y,w)); } rpp(i,n) fa[i]=i; ll ans=0; ll cnt=n; rep(i,ed0.size()) { ll f1=find(ed0[i].u),f2=find(ed0[i].v); if(f1!=f2) fa[f2]=f1,--cnt;//连通块个数减一 ans+=ed0[i].w; } sort(all(ed1)); rep(i,ed1.size()) { if(k==0) break; ll f1=find(ed1[i].u),f2=find(ed1[i].v); if(f1!=f2) fa[f2]=f1,--cnt,--k,ans+=ed1[i].w; else ed2.push_back(ed1[i]); } sort(all(ed2)); rep(i,ed2.size()) { if(k==0) break; ans+=ed2[i].w; --k; } if(cnt>1) cout<<"-1"<<endl; else cout<<ans<<endl; } return 0; }