解题思路
地图很小,可以考虑二进制枚举。
首先读到地图数据之后,先把k处理一下,可以先求地图全部和,如果直接输出,我懒就没写。
后面用二进制枚举,去枚举到全部可能选的行。
如果枚举到这一行被选中,那么直接累加到答案。
如果枚举这一行未被选中,那么累加到列的和当中。
处理全部的行之后,对列和排序,从大到小累加进答案。再把这个答案和最终答案求最大值即可。
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 16; int mapp[N][N], sum[N]; int main() { ios::sync_with_stdio(false); cout.tie(0); cin.tie(0); int n, m, k; cin >> n >> m >> k; k=min(k,min(n,m)); for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) cin >> mapp[i][j]; int ans = 0; for (int i = 0; i < 1 << m; ++i) { int cnt = __builtin_popcount(i); //统计32位无符号整数的二进制1个数 if (cnt > k) continue; memset(sum, 0, sizeof(sum)); int ret = 0; for (int j = 1; j <= n; ++j) { for (int y = 0; y < m; ++y) if ((1 << y) & i) ret += mapp[j][y + 1]; else sum[j] += mapp[j][y + 1]; } sort(sum + 1, sum + 1 + n, greater<int>()); for (int j = 1; j <= k - cnt; ++j) ret += sum[j]; ans = max(ans, ret); } cout << ans << endl; return 0; }
后话
这里是我但是比赛时,还没想到二进制枚举的思路,直接暴力模拟,得分95分,4MS左右,实在不会证明它对,可是又答不上哪里不对。
可惜是ACM,错一个样例就是WA,OI的话95分也不错了呢。
这里看到了雨巨的题解!!太厉害啦,懂了。
当前不拿最大不代表我以后就拿不到了,当前一直拿最大会多拿很多不应该拿的
#include <bits/stdc++.h> using namespace std; int main (){ int n,m,k; scanf("%d %d %d",&n,&m,&k); int mapp[20][20]; int ans[20+20]; for(int i=0; i<n; ++i) for(int j=0; j<m; ++j) scanf("%d",&mapp[i][j]); int num=0; memset(ans,0,sizeof(ans)); for(int i=0; i<n; ++i) for(int j=0; j<m; ++j) //把行和放进前n项 ans[i]+=mapp[i][j]; for(int i=0; i<m; ++i) for(int j=0; j<n; ++j) //把列和放进后n项 ans[i+n]+=mapp[j][i]; while(k--){ int maxdata=ans[0],maxi=0; for(int i=1; i<m+n; ++i) //找到行最大或列最大 if(ans[i]>ans[maxi]){ maxi=i; maxdata=ans[i]; } num+=maxdata; ans[maxi]=0; if(maxi<n) for(int i=0; i<m; ++i) ans[i+n]-=mapp[maxi][i]; //这一行所在列全部减掉当前值 else for(int i=0; i<n; ++i) ans[i]-=mapp[i][maxi-n]; //同理 } printf("%d\n",num); return 0; } //……哎,只能说当时太弱了吧,想当然了