木棍 Sticks「POI2011 R3 Day2

题目

若干彩色的木棍,求是否存在三根互不同色的木棍,能够构成一个非退化的三角形(即面积为正的三角形)。

输入格式

第一行一个正整数表示颜色种类数。
接下来行,每行若干个空格隔开的正整数,描述木棍。第行第一个数为,表示颜色的木棍数。该行接下来个正整数,描述这种颜色的木棍的长度。

输出格式

  • 若不存在,则输出一行NIE;
  • 否则,输出一行六个空格隔开的数,分别表示第一根木棍的颜色,第一根木棍的长度,第二根木棍的颜色,第二根木棍的长度,第三根木棍的颜色,以及第三根木棍的长度。

如果有多解,任意输出一个即可。

样例

样例输入 1

4
1 42
2 6 9
3 8 4 8
1 12

样例输出 1

3 8 4 12 2 9

样例输入 2

3
1 1
1 2
1 3

样例输出 2

NIE

 

题解&分析:

首先由于是一个三角形,所以对于三条边最接近是最好搜索的,也是最好找的

如果没有颜色标号,这道题怎么做呢?

很简单了,就是从小到大排序后枚举相邻的两条边,假设这两条边为更长的两条边,然后直接去寻找第三条边即可

可是有颜色标号,怎么办?

还是先排序

对于有连续的一段的区间的颜色都相等,那记录这段区间的最大值和最小值(马上解释为什么这样做)

那么现在新的数组里面不会存在有连续的两个点是同样颜色的

那么枚举新数组的i(i里存了两个值是最大值和最小值),将i的最大值与i+1的最小值作为较长的两条边

然后找第三边,这就是为什么记录最大值与最小值原因

那么第三边怎么找呢?

由于三角形是三条不同颜色的边组成的,那么如果记录了前i-1个点中三个颜色互不相同的最长边,那么答案就会从这三条边中出来,至于怎么维护,具体看代码。。。。

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <climits>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define ll long long
const int MAXN = 1e6 + 4;
int k , n , cnt;
ll id[4] , mx[4];//id存的是那三条边的颜色,mx存长度
struct node{
    ll l , r;
    ll col;
    friend bool operator < ( node a , node b ){
        return a.l < b.l;
    }
}a[MAXN] , s[MAXN];

int main(){
    scanf( "%d" , &k );
    for( int i = 1 ; i <= k ; i ++ ){
        int num;scanf( "%d" , &num );
        while( num -- ){
            ll x;scanf( "%lld" , &x );
            a[++cnt].col = i , a[cnt].l = x;
        }
    }
    sort( a + 1,  a + cnt + 1 );
    ll color = 0 , last = 0;
    for( int i = 1 ; i <= cnt; i ++ ){
        if( a[i].col != color ){
            s[n++].r = last;
            s[n].col = color = a[i].col;
            s[n].l = last = a[i].l;
        }
        else
            last = a[i].l;
    }
    for( int i = 1 ; i < n ; i ++ ){
        ll now = 0;
        for( int j = 1 ; j <= 3 ; j ++ ){
            if( id[j] != s[i].col && id[j]!= s[i+1].col ){
                if( mx[now] < mx[j] )
                    now = j;//找最大的显然最好
            }
        }
        if( now && mx[now] + s[i].r > s[i+1].l ){
            printf( "%lld %lld %lld %lld %lld %lld\n" , id[now] , mx[now] , s[i].col , s[i].r , s[i+1].col , s[i+1].l );//找到了,直接输出
            exit( 0 );
        }
        bool flag = 0;
        now = 1;
        for( int j = 1 ; j <= 3; j ++ ){//这就是维护方法,将s[i].r存进mx[]数组中来
            if( id[j] == s[i].col ){//如果它的颜色在那三条边颜色中的出现过,直接替换
                mx[j] = s[i].r;
                flag = 1;
                break;
            }
            else if( mx[j] < mx[now] )
                now = j;
        }
        if( !flag ){
            id[now] = s[i].col;//否则选择最小的一条边将其替换成s[i].r , s[i].col
            mx[now] = s[i].r;
        }
    }
    printf( "NIE\n" );
    return 0;
}

还需要多练贪心,需要更多练习....

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页