hdu 4253

 
 


陈题, 有篇论文, 利用了N多生成树的性质,大体思想就是通过调整某种边的权值后生成一个最小生成树, 这个新树所分的结构是与原树2种边按此分法生成的最小生成树是最优的, 这样就转换成了一种枚举一种边增加的权值后的生成树的算法, 而且我们要找的是一个区间

 

http://oj.tsinsen.com/resources/Train2012-test-clj-tree.pdf

 

 

#include <cstdio>
#include <algorithm>

using namespace std;

const int M=100000+123;
const int N=50000+123;
struct Edge{
    int u, v, w;
}B[M], W[M];
int cntB, cntW;

int p[N], rank[N];

int find(int x)
{
    return (p[x]==x?x:p[x]=find(p[x]));
}

void init(int x)
{
    for (int i=0; i<x; ++i) p[i]=i, rank[i]=1;
}

int ans;
int kruskal(int x, int n)/// 同权值先加黑边
{
    init(n);
    int pb=0, pw=0;
    int res=0;
    while (pb<cntB || pw<cntW)
    {
        //printf("pb=%d pw=%d\n", pb, pw);
        if((B[pb].w>W[pw].w+x && pb<cntB && pw<cntW) || pb>=cntB)
        {
            int fa=find(W[pw].u), fb=find(W[pw].v);
            //printf("u=%d v=%d fu=%d fv=%d pu=%d pv=%d\n", W[pw].u, W[pw].v, fa, fb, p[W[pw].u], p[W[pw].v]);
            if(fa!=fb)
            {
                if(rank[fa]<rank[fb])
                {
                    p[fa]=fb;
                    rank[fb]+=rank[fa];
                }
                else
                    p[fb]=fa, rank[fa]+=rank[fb];
                ans+=W[pw].w;
                res++;
            }
            pw++;
        }
        else
        {
            int fa=find(B[pb].u), fb=find(B[pb].v);
            if(fa!=fb)
            {
                if(rank[fa]<rank[fb])
                {
                    p[fa]=fb;
                    rank[fb]+=rank[fa];
                }
                else
                    p[fb]=fa, rank[fa]+=rank[fb];
                ans+=B[pb].w;
            }
            pb++;
        }
    }
    return res;
}

bool cmp(Edge a, Edge b)
{
    return a.w<b.w;
}

int main()
{
    int n, m, k;
    int T=0;
    //freopen("tree.in", "r", stdin);
    //freopen("tree1.out", "w", stdout);
    while (~scanf("%d%d%d", &n, &m, &k))
    {
        cntB=cntW=0;
        for (int i=0; i<m; ++i)
        {
            int a, b, c, x; scanf("%d%d%d%d", &a, &b, &c, &x);
            if(x) B[cntB].u=a, B[cntB].v=b, B[cntB++].w=c;
            else W[cntW].u=a, W[cntW].v=b, W[cntW++].w=c;
        }
        sort(W, W+cntW, cmp);
        sort(B, B+cntB, cmp);
        int l=-101, r=101, mid;
        while (l<=r)
        {
            mid=(l+r)>>1;
            ans=0;
            int ld=kruskal(mid, n);
            ans=0;
            int rd=kruskal(mid-1, n);
            ans+=(rd-k)*mid;
            if(ld<=k && k<=rd)break;
            if(k<ld)l=mid+1;
            if(k>rd)r=mid-1;
            //printf("%d %d  %d %d %d\n", l, r, ld, rd, ans);
        }
        printf("Case %d: %d\n", ++T, ans);
    }
    return 0;
}


void merge(int a, int b, int color, int &pp, int &res)
{
    int fa=find(a), fb=find(b);
            //printf("u=%d v=%d fu=%d fv=%d pu=%d pv=%d\n", W[pw].u, W[pw].v, fa, fb, p[W[pw].u], p[W[pw].v]);
    if(fa!=fb)
    {
        if(rank[fa]<rank[fb])
        {
            p[fa]=fb;
            rank[fb]+=rank[fa];
        }
        else
            p[fb]=fa, rank[fa]+=rank[fb];
        if(!color)ans+=W[pp].w;
        else ans+=B[pp].w;
        if(!color)res++;
    }
    pp++;
}

int kruskal(int x, int n)/// 同权值先加黑边
{
    init(n);
    int pb=0, pw=0;
    int res=0;
    while (pb<cntB && pw<cntW)
    {
        //printf("pb=%d pw=%d\n", pb, pw);
        if((B[pb].w>W[pw].w+x && pb<cntB && pw<cntW) || pb>=cntB)
        {
            merge(W[pw].u, W[pw].v, 0, pw, res);
        }
        else
        {
            merge(B[pw].u, B[pw].v, 1, pb, res);
        }
    }
    while (pb<cntB)merge(B[pw].u, B[pw].v, 1, pb, res);
    while (pw<cntW)merge(W[pw].u, W[pw].v, 0, pw, res);
    return res;
}


你可能感兴趣的:(c,算法,struct,tree,merge,IM)