Niuke Practice 58:Matrix Elimination Game(貪欲な01文字列列挙)

トピック: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;
}

おすすめ

転載: blog.csdn.net/u011612364/article/details/104620978