#洛谷oj:P1525 [NOIP2010 提高组] 关押罪犯

洛谷oj:P1525 [NOIP2010 提高组] 关押罪犯

#题目描述
在这里插入图片描述

#一看很明显是贪心算法 加排序 因为 这个中间最大值的那一对肯定是不会在一起的 从大到小来看 所有点对都尽量不要在一个监狱
#带权并查集 这个想不出来 只想到了并查集 来判段是不是在一个监狱 想不出怎么合并 (⊙ˍ⊙)

#知识点
并查集 贪心 排序 二分图(不了解)

#代码
第一次
10分 我想的是两个都不确定的情况就两种情况都试试 再来找小的那个值

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<stdio.h>
using namespace std;
int relat[20010];
int root[20010];
int sum[3];
int n,m,a,b,c,ans;
struct node
{
    int x;
    int y;
    int z;
} Data[100020];
bool cmp(node a,node b)
{
    return a.z < b.z;
}
void init()
{
    for(int i=1; i<=n; i++)
    {
        root[i] = 0;
    }
    int i = m;
    root[Data[i].x] = 1;
    root[Data[i].y] = 2;
    //cout << Data[i].x <<" "<< 1 <<"   " <<Data[i].y  <<"   " << 2 <<endl;
    for(int i=0; i<3; i++)
    {
        sum[i] = 0;
    }
}
void dfs(int step)
{
    if(step == 0)
    {
        ans = min(sum[1],sum[2]);
//        cout << "有值了 " <<"ans = "<< ans <<endl;
        return ;
    }
    int a = Data[step].x;
    int b = Data[step].y;
//    cout << a <<" 和 "<< b <<"有矛盾   值为 " <<Data[step].z <<endl;
//    cout << root[a] << "  " <<root[b] <<endl;
    if(root[a] == root[b])//在同一个监狱  会有问题
    {
        if(root[a] == 0)//没出现过
        {
            //先将a放到 1 b放到2 再倒过来试试
            root[a] = 1;
            root[b] = 2;
            dfs(step-1);
            root[a] = 2;
            root[b] = 1;
            dfs(step-1);
        }
        else
        {
            sum[root[a]] = max(sum[root[a]],Data[step].z);
            dfs(step-1);
        }
    }
    else if(root[a] == 1) //在一号监狱
    {
        if(root[b] == 0)
        {
            root[b] = 2;
        }
        dfs(step-1);
    }
    else if(root[a] == 2) //在2号监狱
    {
        if(root[b] == 0)
        {
            root[b] = 1;
        }
        dfs(step-1);
    }
    else if(root[a] == 0) //没出现过
    {
        if(root[b] == 1)
        {
            root[a] = 2;
        }
        else if(root[b] == 2)
        {
            root[a] = 1;
        }
        dfs(step-1);
    }

}
int main()
{
    cin >> n >> m;
    for(int i =1; i<= m ; i++)
    {
        cin >> a >> b >> c;
        Data[i].x = a;
        Data[i].y = b;
        Data[i].z = c;
    }
    sort(Data+1,Data+1+m,cmp);
    init();
//    for(int i=1; i<=n; i++)
//    {
//        cout << i << "  " <<root[i] <<endl;
//    }
    ans = 0x3f3f3f3f;
    dfs(m-1);
    cout << ans <<endl;
    return 0;
}

第二次
后来改用了遍历 这个监狱 发现比第一种 递归还差 因为放在那个监狱当前不知道不代表之后不知道 有很大的局限性 后来看来看大佬的想法 (敌人的敌人对我不会是最差的那个) 这样的想法来合并 秒啊!!! (≧0≦)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<stdio.h>
using namespace std;
int relat[20010];
int root[20010];
int n,m,a,b,c,ans;
struct node
{
    int x;
    int y;
    int z;
} Data[100020];
bool cmp(node a,node b)
{
    return a.z > b.z;
}
void init()
{
    for(int i=1; i<=n; i++)
    {
        root[i] = i;
    }
    memset(relat,0,sizeof(relat));
}
int Find(int a)
{
    if(a == root[a])
        return a;
    else
    {
        root[a] = Find(root[a]);
        return root[a];
    }
}
int main()
{
    cin >> n >> m;
    for(int i=1;i<=m;i++)
    {
        cin >> Data[i].x >> Data[i].y >> Data[i].z ;
    }
    sort(Data+1,Data+1+m,cmp);
    init();
//    for(int i=1;i<=m;i++)
//    {
//        cout << Data[i].x <<"-" <<root[Data[i].x] <<" "<<Data[i].y <<"-" <<root[Data[i].y] <<endl;
//    }
    for(int i=1;i<=m+1;i++)//m+1时  有相同的根  所以会输出 0 妙啊!!
    {
        int a = Data[i].x;
        int b = Data[i].y;
        int ra = Find(a);
        int rb = Find(b);
        if(ra == rb)
        {
            cout << Data[i].z <<endl;//因为是降序排序  后面的不可能有这个大  这就是最大的了
            break;
        }else // 关系不好 是互相的  这个关系在没有解决  (这个合并的关系 敌人的敌人和我的关系没有对敌人那么不好 可以这么试着理解)
        {
            if(relat[a] == 0)//a 没有关系不好的
            {
                relat[a] = b;//当前这个就是同a关系不好的
            }
            else//a 有关系不好的
            {
               c = relat[a];//b 和这个c 在一个监狱 c是a的敌人
               int rc = Find(c);
               if(rc != rb)
               {
                   root[rc] = rb;
               }
            }

            if(relat[b] == 0)//b 没有关系不好的
            {
                relat[b] = a;//当前这个就是同b关系不好的
            }else//b 有关系不好的
            {
               c = relat[b];//a 和这个c 在一个监狱 c是b的敌人
               int rc = Find(c);
               if(rc != ra)
               {
                   root[rc] = ra;
               }
            }
        }
    }
    return 0;
}

#总结
这个想法要多思考多理解 这是没错的 常话还是有道理的 ^ _ ^

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值