题解:P2072 宗教问题
题解:P2072 宗教问题
算法分析
本题作为 dp 水题,两个回答都能 dp 解决。原理别的 dalao 讲得十分清楚。
但本题的第一回答可以考虑贪心。
贪心分析
只记录集体总数,可以考虑用 set。
dp 考虑时,每个人可以加入前一个集体或新开一组。
进一步想,当前一组未满时,加入是最优的,不可能新开一组。故贪心成立。
贪心代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=1e18;
const int N=1e3+5;
int n,m,k;
int a[N];
int min_num;
int dp_ms[N];
int num;
set<int> s;
signed main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++){
s.insert(a[i]);
if(s.size()>k){
min_num++;
s.clear();
s.insert(a[i]);
}
}
if(s.size()>0) min_num++;
cout<<min_num<<endl;
dp_ms[1]=1;
for(int i=2;i<=n;i++){
dp_ms[i]=inf;
s.clear();
num=0;
for(int j=i;j>=1;j--){
if(s.find(a[j])==s.end()){
num++;
s.insert(a[j]);
}
if(num>k) break;
dp_ms[i]=min(dp_ms[i],dp_ms[j-1]+num);
}
}
cout<<dp_ms[n];
return 0;
}
dp 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=1e18;
const int N=1e3+5;
int n,m,k;
int a[N];
int dp_mn[N];
int dp_ms[N];
int num;
set<int> s;
signed main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
dp_mn[1]=1;
dp_ms[1]=1;
for(int i=2;i<=n;i++){
dp_mn[i]=inf;
dp_ms[i]=inf;
s.clear();
num=0;
for(int j=i;j>=1;j--){
if(s.find(a[j])==s.end()){
num++;
s.insert(a[j]);
}
if(num>k) break;
dp_mn[i]=min(dp_mn[i],dp_mn[j-1]+1);
dp_ms[i]=min(dp_ms[i],dp_ms[j-1]+num);
}
}
cout<<dp_mn[n]<<endl;
cout<<dp_ms[n];
return 0;
}
总结
第一回答,贪心 \(O(n \log n)\),dp \(O(n^2)\)。
第二回答,皆为 \(O(n^2)\)。

浙公网安备 33010602011771号