【每日一题】8月11日题目精讲—矩阵消除游戏
來(lái)源:??途W(wǎng):
時(shí)間限制:C/C++ 1秒,其他語(yǔ)言2秒 空間限制:C/C++ 262144K,其他語(yǔ)言524288K 64bit IO Format: %lld題目描述
牛妹在玩一個(gè)名為矩陣消除的游戲,矩陣的大小是n行m列,第i行第j列的單元格的權(quán)值為ai,j,牛妹可以進(jìn)行k個(gè)回合的游戲,在每個(gè)回合,牛妹可以選擇一行或者選擇一列,然后將這一行或者這一列的所有單元格中的權(quán)值變?yōu)?,同時(shí)牛妹的分?jǐn)?shù)會(huì)加上這一行或者這一列中的所有單元格的權(quán)值的和。
牛妹想最大化她的得分,球球你幫幫她吧!
輸入描述:
第一行三個(gè)整數(shù)n,m,k
接下來(lái)n行每行m個(gè)整數(shù)表示矩陣中各個(gè)單元格的權(quán)值。
輸出描述:
輸出一個(gè)整數(shù)表示牛妹能獲得的最大分?jǐn)?shù)。
示例1
輸入
復(fù)制
輸出
復(fù)制
備注:
題解:
我來(lái)總結(jié)下官方題解:
如果我們考慮一行一行或一列一列的選擇則可以貪心。但實(shí)際上不行,所以我們要把問(wèn)題轉(zhuǎn)化成選若干列
再看看范圍1<n,m<15,這不是等著我們?nèi)ケ┝?#xff1f;
如果我們給出每一列,那每一列的狀態(tài)就是固定的
我們可以用01串來(lái)表示狀態(tài),比如01001表示134行不選,第25行選擇,這樣我們直接枚舉0到2n-1就代表枚舉了00…00到11…11
大致過(guò)程:
T從0~2n-1枚舉,表示行的狀態(tài)
T是一個(gè)十進(jìn)制數(shù),我們轉(zhuǎn)發(fā)成二進(jìn)制,看里面幾個(gè)1(numh),哪些位置是1,進(jìn)行記錄。
T中幾個(gè)1說(shuō)明選幾行,numl=k-numh(T中1的個(gè)數(shù))為選幾列
sum先加上要選的那幾行(T中1的位置)
然后刨去那幾行的數(shù)據(jù),我們對(duì)剩下的數(shù)據(jù)按照每列的和進(jìn)行排序,選擇最高的那numl列
維護(hù)答案即可
整個(gè)過(guò)程實(shí)則為二進(jìn)制轉(zhuǎn)換+貪心
代碼:
我對(duì)官方代碼進(jìn)行了更詳細(xì)的解讀
#include<bits/stdc++.h> using 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串轉(zhuǎn)換過(guò)來(lái)的bool數(shù)組(用bool數(shù)組主要是為了方便大家理解) long long ans = 0; //存答案,注意總和會(huì)超過(guò)int的最大值要用long long int deal(int x) //把x這個(gè)數(shù)字轉(zhuǎn)換成bool數(shù)組 {memset(b, 0, sizeof(b)); //不清數(shù)組會(huì)死!int cnt = 0, i = 1; //cnt存01串里面1的個(gè)數(shù)while (x){if (x&1) //如果x的最后一位是1{cnt++;//記錄其中1的數(shù)量 b[i] =1;//說(shuō)明第i行是被選擇的 }x>>=1; //x右移一位,等價(jià)于除以二取整i++;//到下一行 }return cnt; } int main() { //————————————讀入——————————————scanf("%d%d%d", &n, &m, &k);for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++){scanf("%d", &a[i][j]);sh[i] += a[i][j];//記錄每一行的值 } //————————以上讀入不多說(shuō)————————//——如果k>n或者k>M,那么肯定就把矩陣選完了———— //這里我這么處理主要是因?yàn)槲液竺娴挠袀€(gè)判斷把這種情況給直接continue掉了, //debug的時(shí)候不想的再寫(xiě)別的了就這樣了 //k=n或者m就已經(jīng)能把矩陣選完,所以結(jié)果肯定是一樣的if (k > n) k = n;if (k > m) k = m; //————————————————————————————————————————//—————枚舉選行的所有可能性,貪心處理列——————int tmp = (1<<n) -1; //1<<n就等于2^n,位運(yùn)算不會(huì)的同學(xué)百度一下for (int T =0; T <= tmp; T++) //T用來(lái)枚舉行的狀態(tài){int numh = deal(T);//將狀態(tài)T轉(zhuǎn)為bool數(shù)組,并返回有多少個(gè)1,既要選多少行int numl = k-numh; //numl是要選多少列if (numl > m || numl < 0) continue;//numl>m或者numl<0,說(shuō)明行的方案不對(duì)(其實(shí)也有可能是k太大,這里就是上文說(shuō)的k比較大的時(shí)候直接continue沒(méi)了的地方)。long long sum=0; //sum是本次枚舉的方案的和for (int i = 1; i <= n; i++) if (b[i]) sum += sh[i]; //把選中的行都加上memset(sl, 0, sizeof(sl));//行選得不同矩陣就不同,所以sl數(shù)組每次都要清干凈for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)if (!b[i]) sl[j] += a[i][j]; //第i行沒(méi)有選,j列的和需要加上a[i][j](第i行選了a[i][j]就清零了不能加)sort(sl+1, sl+1+m);//對(duì)每一列的和進(jìn)行排序(刨去指定行) for (int i=1,j=m; i<=numl; i++,j--) sum += sl[j]; //把最大的numl列的和加到方案里ans = max(ans, sum);//維護(hù)答案} //————————————枚舉+貪心結(jié)束——————————————printf("%lld\n", ans);return 0;}總結(jié)
以上是生活随笔為你收集整理的【每日一题】8月11日题目精讲—矩阵消除游戏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 鼠标侧键设置工具X-Mouse安装教程
- 下一篇: 【每日一题】8月12日题目精讲 Mr.