POJ3977 Subset 折半列舉

2021-09-07 11:26:30 字數 1505 閱讀 2639

題目大意是給定n個數的集合,從這個集合中找到乙個非空子集,使得該子集元素和的絕對值最小。假設有多個答案,輸出元素個數最少的那個。   

n最多為35,假設直接列舉顯然是不行的。

可是假設我們將這些數分成兩半後再列舉的話,最多有2^18(262144),此時我們兩半列舉後的結果進行排序後再二分搜尋一下就能夠了。複雜度為o(nlogn) n最多2^18。

#include #include #include #include #include #include #include #include #include #include #include using namespace std;

struct mystruct

;int compp(const void* a1, const void* a2)

else if (dif == 0)

else

return -1;

}mystruct res[2][300000];

inline long long absll(long long x)

else

return x;

}int main()

for (int i = 0; i < n; i++)

int maxn = n - n / 2;

int maxm = n - maxn;

memset(res, 0, sizeof(res));

for (int i = 0; i < 1 << maxn; i++)

}} qsort(res[0], 1 << maxn, sizeof(mystruct), compp);

for (int i = 0; i < 1 << maxm; i++)

}} qsort(res[1], 1 << maxm, sizeof(mystruct), compp);

long long minvalue = 1000000000000000ll;

int mink = 32;

int l = 0;

int r = (1 << maxm);

for (int i = 0; i < 1 << maxn; i++)

}while (r - l > 1)

else

l = mid;

}l = l >= 1 ? l - 1 : l;

for (int k = l; k < (1 << maxm);k++)

}if (curm == 0 && curk == 0)

long long sum = res[1][k].res + res[0][i].res;

if (absll(sum) < minvalue)

else if (absll(sum) == minvalue)

else if (sum > 0)

}} printf("%i64d %d\n", minvalue, mink);

} return 0;

}

poj3977 Subset(折半列舉)

給定n個整數組成的數列 n 35 從中選出乙個子集,使得這個子集的所有元素的值的和的絕對值最小,如果有多組資料滿足的話,選擇子集元素最少的那個。如果單純的列舉的話,這n個數分別有選和不選兩種,所以一共有2 35個子集。很明顯,會超時,但是我們可以將這個整數數列分成兩半,可得每邊最多18個,如果分別進...

POJ 3977 Subset 折半搜尋

題目 給出乙個整數集合,求出非空子集中元素和絕對值最小是多少 元素個數盡量少 題解 分成兩半 爆搜每一半,用map維護前一半的值 每搜出後一半的乙個值就去map裡找和他和絕對值最小的更新答案 include include include include includetypedef long lo...

POJ 3977 Subset 簡單折半列舉

題意 n個數選若干個,使他們和的絕對值最小,如果存在多個解,選擇所選的個數最少的。題解 n為35,列舉所有情況肯定超時,可以列舉一半然後二分找另一半。include include include include include include using namespace std typedef...