题意:
题意是给出n个点,m条边其中有的属于A有的属于B,要求构造最小生成树 并且 包含k条A的边 求最小花费
思路:这题思路有点nb 我们二分一个权值给属于A公司的边加上 我们知道kruskal需要按照权值排序 那么属于A的边一定会靠后点 这样跑一遍kruskal 看看构造出来的是否满足有k条属于A的边 如果不满足那么权值下调 r = mid 否则 权值上调 l = mid 这样单调性就出来了 注意给边加上权值后记得还原 答案的话因为你多加了k个mid权值 k是边数 mid是你二分出来的权值 记得减去
#include <bits/stdc++.h>
using namespace std;
const int N = 50005,M = 100005;
struct node
{
int u,v,w,id;
} a[M];
int n, m, k, ans, res;
int fa[N];
void init()
{
for(int i = 0;i <= n;i ++)
fa[i] = i;
}
int findx(int x)
{
if(fa[x] == x)
return x;
return fa[x] = findx(fa[x]);
}
bool cmp(node a,node b)
{
if(a.w != b.w)
return a.w < b.w;
return a.id < b.id;
}
bool kruskal(int x)
{
for(int i = 0; i < m; i ++)
{
if(a[i].id == 0)
a[i].w += x;
}
init();
sort(a,a + m,cmp);
int cnt = 0;
int sum = n - 1;
res = 0;
for(int i = 0; i < m; i ++)
{
int x = findx(a[i].u);
int y = findx(a[i].v);
if(x != y)
{
fa[x] = y;
res += a[i].w;
sum -= a[i].id;
cnt ++ ;
}
if(cnt == n - 1)
break;
}
for(int i = 0; i < m; i ++)
{
if(a[i].id == 0)
a[i].w -= x;
}
return sum >= k;
}
int main()
{
int cas = 1;
while(~scanf("%d%d%d",&n,&m,&k))
{
ans = 0x3f3f3f3f;
for(int i = 0; i < m; i ++)
scanf("%d%d%d%d",&a[i].u,&a[i].v,&a[i].w,&a[i].id);
int l = -100,r = 100,mid ;
while(l + 1< r)
{
mid = l + r >> 1;
if(kruskal(mid))
l = mid, ans = res - mid * k;
else
r = mid;
}
printf("Case %d: %d\n",cas ++,ans);
}
return 0;
}