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