题意:给你n个长m的不相同的0,1字符串,代表n个人对m个问题的不同回答,问你至少问几个问题可以知道是哪一个人。
dp[i][j]表示问题串为i且答案为j时能否区分所有人。
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
using namespace std;
#define INF 0x3f3f3f3f
int f[(1<<11)+10][(1<<11)+10];
int p[1234];
int n,m;
int dfs(int s1,int s2) //问题为s1答案为s2
{
if(f[s1][s2]!=INF) return f[s1][s2];
int cnt=0;
for(int i=0;i<m;i++)
{
if((p[i]&s1)==s2)
cnt++;
}
if(cnt<2) return f[s1][s2]=0;
for(int i=0;i<n;i++)
{
if((s1&(1<<i))==0)
{
f[s1][s2]=min(f[s1][s2],max(dfs(s1^(1<<i),s2),dfs(s1^(1<<i),(s2^(1<<i))))+1);
}
}
return f[s1][s2];
}
int main()
{
while(cin>>n>>m)
{
if(!n&&!m)break;
string str;
memset(f,INF,sizeof(f));
memset(p,0,sizeof(p));
for(int i=0;i<m;i++)
{
cin>>str;
for(int j=0;j<str.size();j++)
{
if(str[j]=='1')p[i]|=(1<<j);
}
}
cout<<dfs(0,0)<<endl;
}
return 0;
}
Gym - 100676G
题意:n个课程,每天学习一个,在第t天学习第w[i]门课程他会获得t * w[i]的价值,然后这些课程有先后顺序,一个课程有先修课程,必须学完先修才能学这门课程,问你能得到的最大价值。
思路:虽然预先知道这道题是状压dp,但刚看到这题想到了拓扑排序感觉可行,然后wa到弃疗。因为n很小,我们可以直接状态当前已经修过的课程,然后枚举下一个可以修的课程,更新添加了这个课程之后所取得最大值。因为最后要修完所有的课程所以直接输出dp[(1<<n)-1]即可。map字符串处理的方式真是太强了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 200;
const int INF = 1e8 + 5;
int w[maxn],dp[1<<21];
int n, m, pr[25];
bool vis[1<<21];
map<string, int> mp;
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
mp.clear();
scanf("%d%d",&n,&m);
memset(pr, 0, sizeof(pr));
cin.get();
for (int k = 0; k < n; k++)
{
string s, name; int xx = 0;
getline(cin, s); int flag = 1;
for (int i = 0; i < s.size(); i++)
{
if (flag && s[i+1] >= '0' && s[i+1] <= '9')
{
flag = 0; continue;
}
if (flag) name += s[i];
if (!flag) xx = xx * 10 + s[i] - '0';
}
mp[name] = k; w[k] = xx;
}
for (int i = 1; i <= m; i++) {
string s, xx, hh;
getline(cin, s); int flag = 0;
for (int j = 0; j < s.size(); j++) {
if (s[j+1] == '-') {
flag = 1; continue;
}
if (flag == 1 && s[j] == ' ') {
flag = 2; continue;
}
if (flag == 0) xx += s[j];
if (flag == 2) hh += s[j];
}
pr[mp[hh]] |= (1 << mp[xx]); //如果要学习第mp[hh]课程的话要先学习mp[xx]课程
}
for(int i=1;i<(1<<n);i++)
dp[i] = -INF;
dp[0] = 0;
vis[0] = 1;
for (int i=0;i<(1<<n);i++)
{
if (!vis[i]) continue;
int num=0;
for(int j=0;j<n;j++)
{
num+=((i>>j)&1);
}
for(int j=0;j<n;j++)
{
int xx=i|(1<<j);
if(xx!=i)
{
if((i&pr[j])!=pr[j]) continue;
vis[xx]=1;
dp[xx]=max(dp[xx],dp[i]+(num+1)*w[j]);
}
}
}
printf("%d\n",dp[(1<<n)-1]);
}
return 0;
}