標籤:blog os for io div amp
給出K*K的矩陣,每一行取一個數,構成K個數的和,總共有 k^k種可能,從中取出前k個最小的。
一開始犯了錯,因為只要對每行排序,最小的必定是第一列的和,然後我當時就想著,逐步推進,每次將某行的那個數變成其下一列那個數,當然間距要最小。我這樣明顯是不對的,這樣的話每個數只用了一次,而題目的意思明顯是可以重複多次。
然後大白上說的是把他看成兩行,即每次處理兩行,留下最小的k個 再與下一次讀入的那一行繼續處理。這個方法相當給力,不過有個痛點是,怎麼在兩行的時候,比較快的得到前k小的,我試過全部算一遍, k^k種情況。。會逾時。。之後想了很久 都沒想出一個比較有效方法,後來看到一種很叼的方法,而且很容易證明,即 先把
排完序後的 第一行的 A【0】 到 A【K-1】 分別和 第二行的B【0】組成 最早的k個數,目前只知道A【0】+B【0】是最小的,其餘的還不確定,但是我可以確定的是,第二小的,一定是A【0】+B【1】或者上述k-1個數中的某一個,也就是說,我把這些數,放入優先隊列裡面,然後每次pop出最小的數,輸出,然後把剛剛最小的數的下一個又push進隊列裡面,則下一個pop出來的 必定是第二小的。。。這樣的話 這樣 重複k次,便能得到 前k小的數
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>using namespace std;struct node{ int s,b; bool operator < (const node& rhs) const{ return s>rhs.s; }};priority_queue<node> q;const int N=800;int n;int A[N];int B[N];void solve(){ while (!q.empty()) q.pop(); for (int i=0;i<n;i++){ q.push((node){A[i]+B[0],0}); } int cnt=0; while (cnt<n){ node tmp=q.top(); q.pop(); A[cnt++]=tmp.s; q.push((node){tmp.s-B[tmp.b]+B[tmp.b+1],tmp.b+1}); }}int main(){ while (scanf("%d",&n)!=EOF) { while (!q.empty()) q.pop(); for (int i=0;i<n;i++){ scanf("%d",&A[i]); } for (int i=1;i<n;i++){ for (int j=0;j<n;j++){ scanf("%d",&B[j]); } sort(B,B+n); solve(); } printf("%d",A[0]); for (int i=1;i<n;i++){ printf(" %d",A[i]); } puts(""); } return 0;}