P1525 [NOIP2010 提高组] 关押罪犯

警察局长面临将N名罪犯在两座监狱中重新分配的问题,以最小化年度冲突事件的最大影响力,避免市长不满。通过将罪犯间的仇恨关系转化为无向图,采用二分图的方法寻找最佳分配方案,确保影响力最小的冲突事件尽可能小。

P1525 关押罪犯

题目描述

S 城现有两座监狱,一共关押着 N N N 名罪犯,编号分别为 1 − N 1-N 1N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为 c c c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为 c c c 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到 S 城 Z 市长那里。公务繁忙的 Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。

在详细考察了 N N N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。

那么,应如何分配罪犯,才能使 Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?
Link

思路

这道题,凭借直觉,就能想到将罪犯当做点,罪犯之间的仇恨关系当做点与点之间的无向边,那么原问题变成:将所有点分成两组,使得各组内边权重最大值尽可能小。
所以,接下来咋做呢?
如果我第一步先把怨恨程度最大的一对罪犯分别放到两个监狱里,那接下来第二大,第三大的组,要尽可能分开是肯定的,但分开之后分别放到哪个监狱里呢?

那些有一切东西而没有您的人,我的上帝,在讥笑着那些没有别的东西而只有您的人呢。——泰戈尔

人要有信仰,做题要有目标。目标来自何方?二分才是正道。

没有“目标”时,求起来是十分的迷茫,但如果有了一个目标,我就清楚地知道,哪些边,考虑;哪些边,不考虑。当我们把不需要考虑的边忽略,这个问题就变成了一个二分图的问题。

Code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

int n,m;
int t[20010],edge[200010],v[200010],nex[200010],cnt;
int col[20010];

void add(int _,int __,int ___)
{
    edge[++cnt]=__;
    v[cnt]=___;
    nex[cnt]=t[_];
    t[_]=cnt;
}

bool dfs(int u,int c,int lim)
{
    col[u]=c;
    for(int i=t[u];i;i=nex[i])
    {
        if(v[i]<=lim)continue;
        int _=edge[i];
        if(col[_])
        {
            if(col[_]==c)return false;
        }
        else if(!dfs(_,3-c,lim))return false;
    }
    return true;
}

bool jud(int lim)
{
    memset(col,0,sizeof(col));
    for(int i=1;i<=n;i++)if(col[i]==0)if(!dfs(i,1,lim))return false;
    return true;
}

int main()
{
    cin>>n>>m;
    while(m--)
    {
        int _,__,___;
        scanf("%d%d%d",&_,&__,&___);
        add(_,__,___);
        add(__,_,___);
    }
    int l=0,r=1e9;
    while(l<r)
    {
        int mid=(l+r)/2;
        if(jud(mid))r=mid;
        else l=mid+1;
    }
    cout<<l<<endl;
    return 0;
}

我无处不在。——二分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值