トピック:HTTPS://ac.nowcoder.com/acm/contest/4090/C
https://ac.nowcoder.com/acm/problem/blogs/200190
問題の解決策の巨人、非常に詳細で便利
このトピックは貪欲ですが、一般的な貪欲よりも少し複雑です。このトピックでは、データ範囲が比較的狭いため、より暴力的な方法を使用できます。
最初の知識のポイントは次のとおりです。01文字列の列挙。
いわゆる01文字列の列挙は、各個人が2つの選択肢に直面したときに、01文字列を使用
して、状態圧力dpに類似性があることを示すことができることを意味します。これは、状態を表すために2進数を使用し、1が選択され、0が選択されない、
および別の重要なプロパティがあります。10進数に変換された後、長さがn未満のすべての01文字列は、すべて2未満の数値です^ n。
これはよく理解されています。たとえば、長さ6の最大バイナリ値は111111であり、これは10進数63に変換されます。したがって、バイナリシステムに変換される[0,63]の範囲は、長さ6のすべての選択肢を表すことができます。です。
これが次の貪欲を続けるのに良いことを知っているので、ループ内の列選択を変更するだけでよく、残りの行は固定列選択の下で大から小に貪欲にソートされます。
その他の知識ポイント:__ builtin_popcount()
GCCには、バイナリ関数の数を正確に計算できる__builtin_popcountという組み込み関数があります。ただし、__ builtin_ctzとは異なり、ハードウェア命令に変換されません(少なくともx86では)。代わりに、ビット検索に上記の方法と同様のテーブルベースの方法を使用します。これは間違いなく非常に効率的で非常に便利です。
ビット操作
のnビット左、及びそれぞれのn ^ X * 2と同等であり、左シフト、右シフトのために二倍拡大するXシフトに相当するX << nが、反対である。
&テイクするために使用され0、|は、
マイクロコントローラーで1を設定するために使用されます。インプレース操作を使用します。
以下のコードを入力してください。
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f;
const int N=20;
using namespace std;
typedef long long ll;
int a[N][N];
int s[N];
bool cmp(int x,int y){
return x>y;
}
int main ()
{
//freopen("D:\\input.txt", "r", stdin);
//freopen("D:\\output.txt", "w", stdout);
int n,m,k,ans,res;
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>>a[i][j];
ans=0;
for(int i=0;i<(1<<m);i++){
//2的m次方-1的二进制代表所有被选的情况
memset(s,0,sizeof(s));//每次对选后每一行的sum和清零
res=0;
int tol=__builtin_popcount(i);//二进制有多少个1
if(tol>k)continue;
for(int j=1;j<=n;j++){
for(int k=0;k<m;k++){
if((1<<k)&i)//判断具体的第j行上的每一个是否被选
res+=a[j][k+1];
else
s[j]+=a[j][k+1];
}
}
sort(s+1,s+n+1,cmp);//剩下的行从大到小排序
for(int j=1;j<=k-tol;j++)
res+=s[j];
ans=max(ans,res);
}
cout<<ans<<endl;
return 0;
}