bzoj2654: tree

易水人去,明月如霜。

Description

給你一個無向帶權連通圖,每條邊是黑色或白色。讓你求一棵最小權的恰好有need條白色邊的生成樹。
題目保證有解。

Input

第一行V,E,need分別表示點數,邊數和需要的白色邊數。
接下來E行,每行s,t,c,col表示這邊的端點(點從0開始標號),邊權,顏色(0白色1黑色)。

Output

一行表示所求生成樹的邊權和。
V<=50000,E<=100000,所有數據邊權爲[1,100]中的正整數。

Sample Input

2 2 1
0 1 1 1
0 1 2 0

Sample Output

2
思路:

光光要求有K條白色的邊並不好解決,我們可以思考一下,我們要恰好K條白色的邊,那麼如果給白色的邊都加上一個固定的權值X,我們可以發現,如果X越大,那麼白色邊的數量就越少,對此,我們可以二分一下,加入的權值,求出一個最小的權使得,選擇白色邊的數量恰好爲K

代碼:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define maxn 100005
using namespace std;
int read()
{
    char ch;int s=0,f=1;ch=getchar();
    while(ch>'9'||ch<'0') { if(ch=='-') f*=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') s=s*10+ch-48,ch=getchar();
    return s*f;
}
struct node {
 int u,v,w,c;
}e[maxn];
int u[maxn],v[maxn],w[maxn],c[maxn];
int fa[maxn];
int find(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
bool cmp(const node &a,const node &b)
{
    if(a.w==b.w) return a.c<b.c;
    else return a.w<b.w;
}
int n,m,k;
int ans;
int nod;
bool check(int x)
{
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++) {e[i].u=u[i],e[i].v=v[i],e[i].w=w[i],e[i].c=c[i]; if(!c[i]) e[i].w+=x; }
    sort(e+1,e+1+m,cmp);
    ans=0,nod=0;
    for(int i=1;i<=m;i++)
    {
        int r1=find(e[i].u),r2=find(e[i].v);
        if(r1!=r2)
        {
            fa[r1]=r2;
            ans+=e[i].w;
            if(!e[i].c) nod++;
        }

    }
    ans-=nod*x;
    return nod>=k;
}
void work()
{
  int anns;
 int l=-100,r=100,mid;
 while(l<=r)
 {
     mid=(l+r)/2;
     if(check(mid)) l=mid+1,anns=ans;
     else r=mid-1;
 }
 printf("%d",ans);
}
int main()
{
 n=read(),m=read(),k=read();
 for(int i=1;i<=m;i++) u[i]=read(),v[i]=read(),w[i]=read(),c[i]=read(),u[i]++,v[i]++;
 work();
 return 0;
}


發佈了105 篇原創文章 · 獲贊 10 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章