• P2323 [HNOI2006]公路修建问题


    \(update\)
    如果按照正确理解题意的情况下, 好多题解的代码都错的啊,但毕竟十几年前的题了,数据水了

    二分

    一眼二分

    • 最后输出答案前一定要\(check\)一遍最优解,才能得到正确的方案
    const int N=10010,M=20010;
    struct Edge
    {
        int a,b,c;
    }e1[M],e2[M];
    int p[N];
    PII ans[N];
    int n,m,k;
    
    int find(int x)
    {
        if(x != p[x]) p[x]=find(p[x]);
        return p[x];
    }
    
    bool check(int mid)
    {
        for(int i=1;i<=n;i++) p[i]=i;
    
        int cnt=0;
        for(int i=0;i<m;i++)
        {
            int a=e1[i].a,b=e1[i].b,c=e1[i].c;
            int pa=find(a),pb=find(b);
            if(c<=mid && pa != pb)
            {
                p[pa]=pb;
                ans[cnt++]={i+1,1};
            }
        }
    
        if(cnt < k) return false;
    
        for(int i=0;i<m;i++)
        {
            int a=e2[i].a,b=e2[i].b,c=e2[i].c;
            int pa=find(a),pb=find(b);
            if(c<=mid && pa != pb)
            {
                p[pa]=pb;
                ans[cnt++]={i+1,2};
            }
        }
    
        return cnt==n-1;
    }
    
    int main()
    {
        cin>>n>>k>>m;
        m--;
    
        int l=0,r=0;
    
        for(int i=0;i<m;i++)
        {
            int a,b,c1,c2;
            cin>>a>>b>>c1>>c2;
            e1[i]={a,b,c1};
            e2[i]={a,b,c2};
            r=max(r,c1);
        }
    
        while(l<r)
        {
            int mid=l+r>>1;
            if(check(mid)) r=mid;
            else l=mid+1;
        }
    
        cout<<l<<endl;
    
        check(l);
        for(int i=0;i<n-1;i++) cout<<ans[i].fi<<' '<<ans[i].se<<endl;
    
        //system("pause");
    }
    

    贪心

    • 要求至少有k条一级公路,那我们就排一遍序,按照C1来排序,使用并查集来判断是否添加成功。

    • 当添加了k次成功之后(注意不是前k条,是成功K条),再将剩下的元素再次排序,这次是按照C1与C2的最小值来排序的,再次使用并查集判断加边,直到所有的点都在同一个集合,那么答案自然就出来了。

    const int N=10010,M=20010;
    struct Node
    {
        int id,a,b,c1,c2;
    }e[M];
    int p[N];
    PII ans[N];
    int n,m,k;
    
    int find(int x)
    {
        if(x != p[x]) p[x]=find(p[x]);
        return p[x];
    }
    
    bool cmp1(Node &a,Node &b)
    {
        return a.c1<b.c1;
    }
    
    bool cmp2(Node &a,Node &b)
    {
        return min(a.c1,a.c2)<min(b.c1,b.c2);
    }
    
    int kruskal()
    {
        for(int i=1;i<=n;i++) p[i]=i;
    
        sort(e,e+m,cmp1);
        int res=0;
        int cnt=0;
        int bg=0;
        for(int i=0;i<m;i++)
        {
            int id=e[i].id,a=e[i].a,b=e[i].b,c=e[i].c1;
            int pa=find(a),pb=find(b);
            if(pa != pb)
            {
                p[pa]=pb;
                res=c;
                ans[cnt++]={id,1};
                if(cnt == k)
                {
                    bg=i+1;
                    break;
                }
            }
        }
    
        sort(e+bg,e+m,cmp2);
        for(int i=bg;i<m;i++)
        {
            int id=e[i].id,a=e[i].a,b=e[i].b,c=min(e[i].c1,e[i].c2);
            int pa=find(a),pb=find(b);
            if(pa != pb)
            {
                p[pa]=pb;
                res=max(res,c);
                int t=e[i].c1<e[i].c2?1:2;
                ans[cnt++]={id,t};
            }
        }
    
        return res;
    }
    
    int main()
    {
        cin>>n>>k>>m;
        m--;
    
        for(int i=0;i<m;i++)
        {
            int a,b,c1,c2;
            cin>>a>>b>>c1>>c2;
            e[i]={i+1,a,b,c1,c2};
        }
    
        int t=kruskal();
        cout<<t<<endl;
    
        sort(ans,ans+n-1);
        for(int i=0;i<n-1;i++) cout<<ans[i].fi<<' '<<ans[i].se<<endl;
    
        //system("pause");
    }
    
  • 相关阅读:
    iOS
    iOS
    iOS
    iOS
    iOS
    iOS
    iOS
    iOS
    iOS
    ajax 几种提交方式
  • 原文地址:https://www.cnblogs.com/fxh0707/p/13768582.html
Copyright © 2020-2023  润新知