这道题目是典型的状压问题,但是还不至于用DP,题目也没让求最优方案,爆搜就行,用两种方法
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5;
int val[N];
typedef map<int, int> R;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T, n, m, k, cnt = 0;
R r;
R::iterator it;
cin >> T;
while (T--)
{
cnt++;
string s;
cin >> n >> m >> k;
memset(val, 0, sizeof(val));
for (int i = 1; i <= n; i++)
{
cin >> s;
for (int j = 0; j < s.size(); j++)
{
if (s[j] == 'A')
{
val[i] |= (1 << j);//将所有的位拆开保存
}
}
}
long long res = 0;
for (int S = 0; S < (1 << m); S++)
{
int ans = 0, s = 0;
r.clear();
for (int i = 1; i <= n; i++)
r[val[i] & S]++;//用s=100,样例为AAB,BAB,ABA,ABB,这样就得到了r[0]=1,r[1]=3,不就是有三对吗,因为s不同所以下标的也不一定相邻,用map好多了
for ( it = r.begin(); it != r.end(); it++)//map会将其下标从小到大排序
{//想一想,如果有不同的,不就能凑出一对吗(在s的条件下,也就是集合为s时)
ans += (s*it->second);//如果说r[0]=0,那么ans就一直为0,没有不同的肯定就不能凑成出一对不同的呗
s += it->second;//这应该算是组合数学里面的公式,求组合数的
}
if (ans >= k)
res++;
}
printf("Case #%d: %d\n", cnt, res);
}
return 0;
}
上面的可能不太直观的得到,看第二种,转载:https://blog.csdn.net/qq_41508508/article/details/81538319
//
// main.cpp
// P1001
//
// Created by jinyu on 2018/8/9.
// Copyright © 2018年 jinyu. All rights reserved.
//
#include <iostream>
using namespace std;
const int MAXN = 1000+7; //问卷份数的最大值 1000
const int MAXS = 1024+7; //状态最大值为 2的10次方
char s[17];
int value[MAXN]; //value[i] 表示第i份问卷的值,A用 “1” 表示,B用 “0” 表示
int visit[MAXS]; //visit[i] 表示在当前问题集合的情况下,状态i出现的次数
int dp[MAXN][MAXS]; //dp[i][state]表示当前state状态在前i份问卷一共有对多少不同
int main(){
int T;
scanf("%d",&T);
int tt = T;
while(tt--){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i = 1;i<=n;i++){
value[i] = 0;
scanf("%s",s+1);
for(int j = 1;j<=m;j++){
if(s[j]=='A'){
value[i]+=(1<<(m-j));
}
}
}
printf("Case #%d: ",T-tt);
if(n*(n-1)/2 < k) printf("0\n"); //n取2的组合数一共有 n*(n-1)/2 种
else{
memset(dp, 0, sizeof(dp));
int ans = 0;
//state表示选中的问题集合,1则代表该问题被选中
//通过按位与&运算,state & value[j] 得到当前state问题集合下问题的答案
//按位与运算的应用:可以获取指定位的数值,如:x&100101 可以得到x的第1,4,6位的数值
//状态转移:dp[j][state] = dp[j-1][state] + (j-1) - visit[nowValue];
// dp[j][state]: 假定第j份和前面j-1份都不同,则可以产生j-1对不同的问卷,加上dp[j-1][state],然后去掉重复的,即减去visit[nowValue]
for(int state = 1;state<(1<<m);++state){ //问题集合至少选1个问题,至多选全部问题
memset(visit, 0, sizeof(visit));
for(int j = 1;j<=n;j++){
int nowValue = state & value[j]; //得到当前state问题集合下问题的答案
dp[j][state] = dp[j-1][state] + (j-1) - visit[nowValue];
visit[nowValue]++;
}
if(dp[n][state]>=k) ans++;
}
printf("%d\n",ans);
}
}
return 0;
}