noip2010关押罪犯解题报告

题目描述

  S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N。他们之间的关系自然也极

不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨

气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之

间的积怨越多。如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并

造成影响力为c 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,

然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,

如果影响很坏,他就会考虑撤换警察局长。

在详细考察了N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在

两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只

要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。那

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

输入描述

第一行为两个正整数N 和M,分别表示罪犯的数目以及存在仇恨的罪犯对数。

接下来的M 行每行为三个正整数aj,bj,cj,表示aj 号和bj 号罪犯之间存在仇恨,其怨气值为cj。数据保证,且每对罪犯组合只出现一次

输出描述

共1 行,为Z 市长看到的那个冲突事件的影响力。如果本年内监狱

中未发生任何冲突事件,请输出0

样例输入 Sample Input

4 6

1 4 2534

2 3 3512

1 2 28351

1 3 6618

2 4 1805

3 4 12884

样例输出 

3512

【数据范围】

对于30%的数据有N≤ 15。

对于70%的数据有N≤ 2000,M≤ 50000。

对于100%的数据有N≤ 20000,M≤ 100000。

 核心程序

for(i=1;i<m+1;i++)
       {
          sa=find(crime[i].a);            
          sb=find(crime[i].b);            
          if(sa==sb)
             {
               ans=i;     
               break;     
             }
          else
          {
              f[sa]=f[find(crime[i].b+n)];
              f[sb]=f[find(crime[i].a+n)];
          }              
       }

数据结构分析:树形结构(二叉)

结构体:
typedef struct
{
   int a,b,anger;        
}Node;

 

算法:并查集(树形),运用递归实现。

 

思路:先给“怨气值”进行排序。

然后找最大的“怨气值”,把对应的两人分到两所监狱去。

再找次大的“怨气值”:(对应的两个人这时有三种情况)

1其中已经有一个人分好了监狱:另一个人分到另一个监狱。

2两个人甲乙都还没分好监狱:找与甲乙有怨的已经在监狱里的所有人,发现其中与甲最怨的是丙,与乙最怨的是丁,找出丙丁中更怨(最怨、更怨:排序顺序靠近大的一段)一点的丙,发现丙在狱1,果断把甲放到狱2,乙放到狱1。

3两个人的监狱都分好了:(又分两种情况)

1)两个人不同监狱:OK不用分了

2)两个人同一个监狱:看来这俩会是最大的冤家(“最终结果”求出)

【若本次没有得出“最终结果”,反复执行第3步】

 

 

#include<stdio.h>
typedef struct
{
   int a,b,anger;        
}Node;

int n,m,ans;
int f[40002];
Node crime[100001];

void qsort(int l,int r)
{
   int i=l,j=r,mid=crime[(i+j)/2].anger;
   while(i<=j)
   {
       while(crime[i].anger>mid) i++;       
       while(crime[j].anger<mid) j--;
       if(i<=j)
       {
           Node t=crime[i];   
           crime[i]=crime[j];    
           crime[j]=t;
           i++;
           j--;    
       }         
   }
   if(i<r)   qsort(i,r); 
   if(j>l)   qsort(l,j);  
}

int find(int x)
{
    if(x!=f[x])
       f[x]=find(f[x]);
    return f[x];
}

int main()
{   int n,m,i,j,sa,sb;
    scanf("%d%d",&n,&m);
    for(i=1;i<m;i++)
    scanf("%d%d%d",&crime[i].a,&crime[i].b,&crime[i].anger);    
    qsort(1,m);
    for(i=1;i<=2*n;i++)
       f[i]=i;
    for(i=1;i<m+1;i++)
       {
          sa=find(crime[i].a);            
          sb=find(crime[i].b);            
          if(sa==sb)
             {
               ans=i;     
               break;     
             }
          else
          {
              f[sa]=f[find(crime[i].b+n)];
              f[sb]=f[find(crime[i].a+n)];
          }              
       }
  printf("%d",crime[ans].anger);     
  return 0;     
}

 

转载于:https://www.cnblogs.com/spadeK/p/3335958.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值