一.糖果(New Online Judge)
#include<bits/stdc++.h>
using namespace std;
int dp[1<<20]; //dp[v]:得到口味为v时需要的最少糖果包数量
int ST[100]; //ST[i]:第i包糖果的口味
int main() {
int n,m,k;
cin>>n>>m>>k;
int tot=(1<<m)-1; //tot:二进制是m个1,表示所有m种口味
memset(dp, -1, sizeof dp);
for (int i=0; i<n; i++) {
int st=0;
for (int j=0; j<k; j++) {
int x;
cin>>x;
st|=(1<<x-1); //状态压缩
}
dp[st]=1; //dp[v]:得到口味为v时需要的最少糖果包数量
ST[i]=st; //ST[i]:第i包糖果的口味
}
for (int i=0; i<=tot; i++) //遍历所有口味组合
if (dp[i]!=-1) //已存在得到口味i的最少糖果包数量
for (int j=0; j<n; j++) { //检查给定的n包糖果
int st=ST[j];
if (dp[i|st]==-1 || dp[i|st]>dp[i]+1) //状态转移
dp[i|st]=dp[i]+1;
}
cout << dp[tot]; //得到所有口味tot的最少糖果包数量
return 0;
}
二.Dynasty Puzzles(线性dp和背包 - Virtual Judge (vjudge.net))
/*题意:给出n个字符串,若有两个字符串s1,s2,如果s1的尾和s2的首相同并且s1的首和s2的尾相同,
则s1和s2可以连在一起,问最后能连在一起的最长字符串的长度;
思路:dp[i][j]表示以i开头以j结尾的字符串的长度,对于字符串str,头为a,尾为b,那么可以得到
状态转移方程:dp[i][a]=max(dp[i][a]+strlen(str),dp[i][b]) */
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int main() {
int n,dp[505][505];
cin>>n;
memset(dp,0,sizeof(dp));
while(n--) {
string s;
cin>>s;
int c=s.size();
int a=s[0]-'a',b=s[c-1]-'a';//用下边0代表a,1代表b(0-25表示a-z)
for(int i=0; i<26; i++) {//匹配之前的字符串,判断首尾是否相同
if(dp[i][a]) {
dp[i][b]=max(dp[i][a]+c,dp[i][b]);//把首尾相同的字符串连接起来
}
}
dp[a][b]=max(dp[a][b],c);//若没有匹配到,给其赋值
}
int ans=0;
for(int i=0; i<26; i++) {
ans=max(ans,dp[i][i]);//遍历首部和尾部相同的字符串
}
printf("%d\n",ans);
return 0;
}
三.Boredom(线性dp和背包 - Virtual Judge (vjudge.net))
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
long long n,m=0,a[100001]={0},dp[100001]={0};
cin>>n;
while(n--){
long long x;
cin>>x;
a[x]++;
m=max(m,x);
}
memcpy(dp, a, sizeof a);
for(int i=2;i<=m;i++){
dp[i]=max(dp[i-1],dp[i-2]+i*a[i]);
}
cout<<dp[m]<<endl;
return 0;
}
三.Cut Ribbon(线性dp和背包 - Virtual Judge (vjudge.net))
//题意: 给你n单位长度的尺子吧,让你尽可能的分多段,
//使得分得的长度为a或b或c,问你最多能分多少段
#include<iostream>
#include<algorithm>
using namespace std;
int dp[4001];
int main()
{
int n,a[3];
int i,j;
while(cin>>n>>a[0]>>a[1]>>a[2])
{
for(i=0;i<=n;i++)
{
dp[i]=-4001;
}
dp[0]=0;
for(i=0;i<3;i++)
{
for(j=a[i];j<=n;j++)
{
dp[j]=max(dp[j],dp[j-a[i]]+1);
}
}
cout<<dp[n]<<endl;
}
return 0;
}
四.路径(P1553 - [蓝桥杯2021初赛] 路径 - New Online Judge (ecustacm.cn))
#include<iostream>
using namespace std;
//辗转相除法(递归)求最大公约数
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b,a%b);
}
//求最小公倍数
int lcm(int a, int b)
{
return a*b/gcd(a,b);
}
int main()
{
//动态规划开辟数组
int dp[3000] = {0};
//求出到每一个点的最短路径,先从第二个点开始
for (int i = 2; i <= 2021; i++)
{
int minValue = 100000000;//警示****该值要开辟的足够大(至少大于该题答案,题主错在这里)
if (i - 21 > 0)//如果大于21,则从i-21开始
{
for (int j = i-21; j < i; j++)
{
//到该点的距离为距离小于等于21的任意一点的最短距离(dp[j]) 加上任意一点
//到该点的距离(即最小公倍数)
//最短距离就是求出上述 距离的最小值
minValue = min(minValue,lcm(j,i) + dp[j]);
}
}
else
{
//否则从1开始
for (int j = 1; j < i; j++)
{
//同上
minValue = min(minValue,lcm(j,i) + dp[j]);
}
}
//该点的最短距离为求得的最小值
dp[i] = minValue;
}
cout << dp[2021] << endl;
return 0;
}
五.回路计算(P1554 - [蓝桥杯2021初赛] 回路计数 - New Online Judge (ecustacm.cn))
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int M=22;
const int N=1<<M;
ll dp[N][M];
int p[M][M];
int gcd(int a,int b) {
if(a%b==0) return b;
return gcd(b,a%b);
}
void getpath() {
for(int i=1; i<=21; i++) {
for(int j=1; j<=21; j++)
if(i==j) p[i-1][j-1]=0;//p[i][j]=1表示i,j互质,互通
else if(gcd(i,j)==1) p[i-1][j-1]=1;//p[i][j]=1表示i,j互质,互通
}
return ;
}
int main() {
getpath();
dp[1][0]=1;//用二进制数i表示经过点的状态
for(int i=0; i<1<<21; i++) {// j表示最终到达的点
for(int j=0; j<21; j++) {
if(i>>j&1) {
for(int k=0; k<21; k++) {
if(i>>k&1&&p[k][j]) {//K点可以到达j点
dp[i][j]+=dp[i-(1<<j)][k];//i-(1<<j)代表上一个状态
}
}
}
}
}
ll ans=0;
for(int i=0; i<21; i++) {
ans+=dp[(1<<21)-1][i];
}
printf("%lld\n",ans);
}
六.(A-瓜瓜打游戏(EASY)_浙江农林大学第二十二届程序设计竞赛(同步) (nowcoder.com))
#include<iostream>
#define ll long long
using namespace std;
ll n,p,a[5001],dp[5001][5001];
int main(){
cin>>n>>p;
for(int i=1;i<=n;i++){
cin>>a[i];
dp[i][0]=1;
}
dp[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
dp[i][j]=(dp[i-1][j]+dp[i-1][j-1]*a[i])%p;
}
for(int i=0;i<=n;i++)
cout<<dp[n][i]<<" ";
return 0;
}
七.砝码称重(P1558 - [蓝桥杯2021初赛] 砝码称重 - New Online Judge (ecustacm.cn))
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[100005];//表示重量为j的称重能不能实现,取值为1或0
ll w[105];//N个砝码的重量
int main()
{
ll N;
cin >> N;
for (ll i = 1; i <= N; i++) cin >> w[i];
memset(dp, 0, sizeof(dp));
dp[0] = 1;
for (ll i = 1; i <= N; i++) {//考虑每个砝码
//从大到小考虑每个称重j,j>=w[i]
//如果从小到大,则意味着w[i]可以加很多次
for (ll j = 100000; j >= w[i]; j--)//此前没有加w[i],现在考虑加
//如果此前dp[j - w[i]]为1,则加上w[i]的重量,能达到j,所以dp[j]为1
dp[j] = max(dp[j], dp[j - w[i]]);
}
for (ll i = 1; i <= N; i++) {
for (ll j = 1; j <= 100000 - w[i]; j++)//此前不放w[i]或放,现在减,相当于放左边和不放
//如果此前dp[j + w[i]]为1,则减去w[i]的重量,能达到j,所以dp[j]为1
dp[j] = max(dp[j], dp[j + w[i]]);
}
ll ans = 0;
for (ll i = 1; i <= 100000; i++)
ans += dp[i];
cout << ans << endl;
return 0;
}