前言
传送门 :
思路
因为数据范围很小, 我们考虑使用
d
p
dp
dp
显然对于每袋 糖果 有 拿和不拿两种状态 , 所以需要使用 背包
同时,又因为 需要 表示当前状态 ,所以考虑使用 状态压缩
状态表示 :
d
p
[
N
]
[
1
<
<
M
]
dp[N][1<<M]
dp[N][1<<M] 表示 从前
i
i
i袋糖果选,状态为
s
s
s的最小集合
状态计算 :
d
p
[
i
]
[
s
]
=
m
i
n
(
d
p
[
i
]
[
s
]
,
d
p
[
i
?
1
]
[
s
&
(
?
w
[
i
]
)
]
+
1
)
(
?
w
[
i
]
表
示
按
位
取
反
,
L
a
t
e
x
打
不
出
来
dp[i][s] =min(dp[i][s],dp[i-1][s\&(-w[i])]+1)(-w[i]表示按位取反,Latex打不出来
dp[i][s]=min(dp[i][s],dp[i?1][s&(?w[i])]+1)(?w[i]表示按位取反,Latex打不出来
因为
N
=
100
N=100
N=100 ,因为空间开销
2
20
?
N
2^{20}*N
220?N 会寄
所以考虑优化
1
1
1维,当然我们跟着 背包 倒序转移即可
Mycode
#include <iostream>
#include <vector>
#include <map>
#include <cstring>
#include <queue>
#include <set>
#include <algorithm>
using namespace std;
#define IOS ios::sync_with_stdio(false);
#define CIT cin.tie(0);
#define COT cout.tie(0);
#define ll long long
#define x first
#define y second
#define pb push_back
#define endl '\n'
#define all(x) (x).begin(),x.end()
#define Fup(i,a,b) for(int i=a;i<=b;i++)
#define Fde(i,a,b) for(int i=a;i>=b;i--)
typedef priority_queue<int,vector<int>,greater<int>> Pri_m;
typedef pair<int,int> pii;
typedef vector<int> VI;
map<int,int> mp;
const int N = 110,M =(1<<20)+10 , INF = 0x3f3f3f3f;
int w[N],f[M],n,m,k;
void solve(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
int x;cin>>x;
w[i]|= 1<<x-1;
}
}
memset(f,0x3f,sizeof f);
f[0] = 0 ;
for(int i=1;i<=n;i++)
for(int s = (1<<m);s>0;s--)
f[s] = min(f[s],f[s&(~w[i])]+1);
if(f[(1<<m)-1] == INF)cout<<-1<<endl;
else cout<<f[(1<<m)-1]<<endl;
}
int main(){
solve();
return 0 ;
}
|