【洛谷】P1626象棋比賽

題目描述

有N個人要參加國際象棋比賽,該比賽要進行K場對弈。每個人最多參加兩場對弈,最少參加零場對弈。每個人都有一個與其他人不相同的等級(用一個正整數來表示)。

在對弈中,等級高的人必須用黑色的棋子,等級低的人必須用白色的棋子。每個人最多隻能用一次黑色的棋子和一次白色的棋子。爲增加比賽的可觀度,觀衆希望K場對弈中雙方的等級差的總和最小。

比如有7個選手,他們的等級分別是30172641193818,要進行3場比賽。最好的安排是選手2對選手7,選手7對選手5,選手6對選手4。此時等級差的總和等於(18-17)+(19-18)+(41-38)=5達到最小。

輸入輸出格式

輸入格式:
第一行兩個正整數NK

接下來有N行,第i行表示第i+1個人等級。

[數據規模]

在90%的數據中,1N3000;

在100%的數據中,1N100000;

保證所有輸入數據中等級的值小於1000000001KN-1。

輸出格式:
在第一行輸出最小的等級差的總和。

輸入輸出樣例

輸入樣例#17 3
30
17
26
41
19
38
18
輸出樣例#15

這道題目看上去沒有任何思路,但是仔細思考,發現這題其實可以用貪心的方法,每次取最小的和然後累加,但是這樣暴力枚舉的時間複雜度異常高,果斷想到小根堆,可是時間複雜度還在O(n^2+nlog2(n))。再想想還能怎麼優化???如果把所有的數排序,然後兩兩作差(爲什麼成立???你問我?其是很簡單!),而它的成立性不言而喻,因爲如果排序後兩兩的差會比其他的大,這顯然不成立,因爲他們兩個數最靠近!!!

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<iostream>
using namespace std;
priority_queue<int>q;
int a[100010];
struct node{
    int u,v,w;
}e[100010];
int f[100010];
int gi(){
    char c=getchar();int f=1,sum=0;
    while((c>'9' || c<'0') && c!='-')
        c=getchar();
    if(c=='-'){f=-1;c=getchar();}
    while(c>='0' && c<='9'){
        sum=sum*10+c-'0';
        c=getchar();
    }
    return f*sum;
}
int find(int x){
    if(f[x]!=x)f[x]=find(f[x]);
    return f[x];
}
void join(int x,int y){
    x=find(x);y=find(y);
    if(x!=y)f[y]=x;
}
int main(){
    int i,j,k,n,m;
    n=gi();k=gi();
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    for(i=1;i<n;i++)
        q.push(a[i]-a[i+1]);
    int ans=0;
    for(i=1;i<=k;i++){
        ans-=q.top();
        q.pop();
    }
    printf("%d\n",ans);
    return 0;
}
發佈了112 篇原創文章 · 獲贊 9 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章