每日一題 8月11日題目精講 矩陣消除遊戲

2021-10-23 19:54:53 字數 2563 閱讀 8162

首先,我們很容易得到,先選哪一行(列),後選哪一行(列),只要選的一樣是不影響結果的,這個我相信大家都能看出來啦……

第二,如果只按行選,或者只按列選,貪心妥妥的(把合最大的幾行加起來就ok啦)。

第三,也是本題第乙個問題:如果只按列選或者只按行選沒有交叉就一定是最大值嗎?

——沒有交叉只能保證選的數字最多,但是未必的最大的,例如:

3 3 2

1 5 1

5 5 5

1 5 1

第四,如果我每次貪心的選剩下的圖中最大的一行或者一列,然後把這一行(列)抹為0可以嗎?(既按照題目描述步驟每一步貪心,這樣的區域性最優解能得到全域性最優解嗎?)

我想這又是乙個可能會坑到的地方。

先也給一組反例:

4 4 3

1 1 9 3

1 8 10 8

1 2 7 2

1 2 2 2

一步一步貪心話先選第三列,第三列清零;然後選第二行,最後選第四列。但是選第二三四列更好哇。這是為什麼?為什麼這樣貪心不對?

——因為你的每次選擇,選一列也好選一行也好,會對後面的選擇造成影響,且不同的選擇造成的影響是不一樣的,你這次先選了最好的一行(列)有可能就會使得後面能選的變少,你沒選最好的一行(列)後面的機會卻更多,這就是不滿足無後效性,就好像裝箱問題:給你乙個體積為v的箱子,再給你若干件體積不同的物品,希望選一些物品盡量裝滿,你會上來就選擇最大的嗎?我們會很容易的想到,也許拼兩個小的比裝乙個大的更好。對於做個題其實也一樣,你選了最大的,後面選的就少了……

再多說兩句,當你有這種懷疑卻不知道對不對的時候怎麼辦呢?

嚴肅認真的方法是爭取數學證明……但是這個方法我其實不太推薦,因為在貪心的方法對的時候,歸納法一般比較好證,但是要歸納法你沒證明出來你就能說他不對嗎?完全有可能是因為不會證……

那麼在沒法證明又懷疑的時候最好的辦法是舉反例,舉反例不是隨便舉例子,是要從你的懷疑入手。以本題為例,什麼情況容易出現反例?我懷疑的就是某一行或者列有幾個數特別大,然後第一次就把他們一起選了,然而事實上可以通過後面的選擇分開選這幾個數。有了這種懷疑之後,你可以輕輕鬆鬆舉出一堆反例,如:

3 3 2

100 100 1

2 4 2

4 2 2

還有乙個稍微取巧一點的事情就是去看一下資料範圍,這個不絕對,但是確實有提醒的作用。你看如果按上述方法貪心,時間複雜度是o(n2m2),這個題的nm都是15,也太小了,牛客這麼好的伺服器,如果這樣可以那出題人為啥不把資料造大一點?

—————————————以下就是本題解法的分隔線—————————————

我們知道如果只是行的選擇或者只是列的選擇就可以貪心。那麼我們就把問題轉化成只選若干列好了!

如果我們想貪心的選取最好的若干列,那麼我們必須提前知道我們選了多少行哪些行,這個怎麼知道呢?看看資料範圍,其實暴力就好了——寫個搜尋,或者用01串列舉。

所謂01串列舉,就是我們在每個個體都面對兩種選擇的時候,可以用乙個01串表示,比如說對於本題,每一行有選和不選兩種可能,假設有5行的話,我們就可以用乙個長度為5的01串來表示,0表示不選1表示選,就像乙個bool陣列一樣,如:01001 表明第134行不選,第25行要選。

只是用乙個數字來表示比用數字表示方便,為什麼方便呢?因為所有長度小於n的01串,轉成十進位制之後就是所有小於2n2^2n的數字,這樣從0到2n−12^-12n−1−1列舉數字就是從00…00列舉到11…11。

具體細節在**裡面有注釋:

01列舉串+貪心

#includeusing namespace std;

int n, m ,k;

int a[20][20];

long long sh[20],sl[20];//sh[i]是第i行的和,sl[i]是第i列的和(在行選完之後用)

bool b[20];//b[i]是01串轉換過來的bool陣列(用bool陣列主要是為了方便大家理解)

long long ans = 0; //存答案,注意總和會超過int的最大值要用long long

int deal(int x) //把x這個數字轉換成bool陣列

x>>=1; //x右移一位,等價於除以二取整

i++;

}return cnt;

}int main()

//————————以上讀入不多說————————

//——如果k>n或者k>m,那麼肯定就把矩陣選完了————

//這裡我這麼處理主要是因為我後面的有個判斷把這種情況給直接continue掉了,

//debug的時候不想的再寫別的了就這樣了

//k=n或者m就已經能把矩陣選完,所以結果肯定是一樣的

if (k > n) k = n;

if (k > m) k = m;

//————————————————————————————————————————

//—————列舉選行的所有可能性,貪心處理列——————

for (int t =0; t <= tmp; t++) //t用來枚舉行的狀態

//————————————列舉+貪心結束——————————————

printf("%lld\n", ans);

return 0;

}

每日一題 4月8日題目精講 黑白樹

試題鏈結 時間限制 c c 1秒,其他語言2秒 空間限制 c c 32768k,其他語言65536k 64bit io format lld 題目描述 一棵n個點的有根樹,1號點為根,相鄰的兩個節點之間的距離為1。樹上每個節點i對應乙個值k i 每個點都有乙個顏色,初始的時候所有點都是白色的。你需要...

每日一題 8月7日題目精講 雙棧排序

時間限制 c c 1秒,其他語言2秒 空間限制 c c 131072k,其他語言262144k 64bit io format lld tom最近在研究乙個有趣的排序問題。如圖所示,通過2個棧s1和s2,tom希望借助以下4種操作實現將輸入序列公升序排序。操作a 如果輸入序列不為空,將第乙個元素壓入...

每日一題 4月7日題目精講 樹

樹 時間限制 c c 1秒,其他語言2秒 空間限制 c c 131072k 其他語言262144k 64bit io format lld 題目描述 shy有一顆樹,樹有n個結點。有k種不同顏色的染料給樹染色。乙個染色方案是合法的,當且僅當對於所有相同顏色的點對 x,y x到y的路徑上的所有點的顏色...