【codeforces 733D】【贪心 乱搞】D. Kostya the Sculptor【给你n个长方形,让你找出2个或1个长方体,使得他们拼接成的长方体的内接圆半径最大】

传送门:http://codeforces.com/contest/733/problem/D

题意:给你n个长方形,让你找出2个或1个长方体,使得他们拼接成的长方体的内接圆半径最大(两个矩形拼接的条件是他们有一个面完全相同)


思路:

很容易想到一个长方体的内接圆半径是由他的最短的那条边决定的,

拼的时候贪心思想就是拼完之后让最小边变大,所以按两条边较长那个面把两个长方体拼起来

纯暴力复杂度是O(n^2)

设长方体的边长从大到小分别为a,b,c,

我们读入的时候将长方体边长排序

然后sort 以a为第一关键字 以b为第二关键字 以c为第三关键字

然后再进行拼接操作复杂度是O(n)


代码:

#include <bits/stdc++.h>
using  namespace  std;
#define ff first
#define ss second
#define rep(i,k,n) for(int i=k;i<=n;i++)
typedef pair<pair<int, int>, pair<int, int> >piii;
template<class T> void read(T&num) {
    char CH; bool F=false;
    for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
    for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
    F && (num=-num);
}

const int N=1e5+10;

piii p[N];
int n, a[3];

int  main(){
  read(n);
  int ans = 0,pos1, pos2 = -1;
  rep(i, 1, n){
    rep(j, 0, 2)read(a[j]);
    sort(a, a + 3);
    p[i] = {{a[1], a[2]}, {a[0], i}};

    if(ans < a[0])ans = a[0], pos1 = i;//不合并
  }  
  sort(p + 1, p + n + 1);

  rep(i, 1, n){
    if(p[i].ff == p[i + 1].ff){//按较大的两条边合并
      int x = p[i].ss.ff + p[i + 1].ss.ff;
      x = min(x, p[i].ff.ff);
      if(ans < x) ans = x, pos1 = p[i].ss.ss, pos2 = p[i + 1].ss.ss;
    }
  }

  if(pos2 == -1){
    printf("1\n%d\n", pos1);
  }
  else{
    printf("2\n%d %d\n", pos1, pos2);
  }
  return 0;
}
PS:巧用pair比手写结构体方便一些


当然当a,b相等时也可以用map找到c最大的两个三元组来更新答案,这样复杂度为O(nlogn)

代码:

(结构体写的,写的有些啰嗦)

#include <bits/stdc++.h>
using  namespace  std;
#define rep(i,k,n) for(int i=k;i<=n;i++)
typedef pair<int, int> P;

const int N=1e5+10;

int a[N][3];
std::map<P, int> mp;
int n;

struct node
{
  int  a[3];
  int pos;
  void st(){
    sort(a, a+3);
  }

  bool operator < (const node& tmp)const{
  if(tmp.a[1]==a[1]){
    if(tmp.a[2]==a[2]){
      return a[0]<tmp.a[0];
    }
    else return a[2]<tmp.a[2];
    }
  else return a[1]<tmp.a[1];
  }
}p[N];



int  main(){
  cin>>n;
  rep(i, 1, n){
    cin>>p[i].a[0]>>p[i].a[1]>>p[i].a[2];
    p[i].pos = i;
    p[i].st();
  }
  sort(p+1, p+n+1);

/*  rep(i, 1, n){//输出
    cout<<p[i].a[0]<<p[i].a[1]<<p[i].a[2]<<endl;
  }*/

  int mx=0, pos1;

  rep(i, 1, n){//不合并
    if(p[i].a[0]>mx)pos1=p[i].pos, mx = p[i].a[0];
  }

  rep(i, 1, n){//添加二元组
    mp[make_pair(p[i].a[1], p[i].a[2])]++;  
  }

  int pos21, pos22,i=1;
  bool flag=false;

  while(i<=n){//合并后
    int sz=mp[make_pair(p[i].a[1], p[i].a[2])];
    if(sz <=1)i++;
    else{
      i += sz;
      int fg = min(p[i-1].a[1], p[i-2].a[0]+p[i-1].a[0]);
      if(fg > mx){
        flag=true;
        mx=fg;
        pos21=p[i-2].pos;
        pos22=p[i-1].pos;
      }
    }
  }

  if(!flag){
    puts("1");
    printf("%d\n", pos1);
  }
  else{
    puts("2");
    printf("%d %d\n", pos21, pos22);
  }
  return 0;
}





 





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值