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");
}
posted @ 2020-10-04 22:04  Dazzling!  阅读(96)  评论(0编辑  收藏  举报