P1048 [NOIP2005 普及组] 采药
本质上是一道01背包问题
递推式:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - tim[i]]+power[i])
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 105;
int T, M;
int tim[maxn];
int power[maxn];
int dp[105][1005];
//定义状态 dp[i][j]为j 为容量为放入前i个物品(按i从小到大的顺序)的最大价值
int main()
{
cin >> T >> M;//T相当于背包总容量,M相当于物品个数
for (int i = 1; i <= M; i++)
cin >> tim[i] >> power[i];
for (int i = 1; i <= M; i++)
{
for (int j =1; j <= T; j++)
{
if (tim[i] <= j)//剩余背包容量大于等于物品的重量
{
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - tim[i]]+power[i]);//递推式,装这个物品或不装这个物品
}
else
dp[i][j] = dp[i - 1][j];//只能不装
}
}
cout << dp[M][T] << "\n";
}
P1616 疯狂的采药
本质上为完全背包问题
递推式为dp[i]=max{dp[j],dp[j-time[i]]+power[i]}
第一层循环为草药个数,第二层循环为采药总时间
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 100005;
int T, M;
int tim[maxn];
int power[maxn];
long long int f[10000005];
//定义状态 dp[i][j]为j 为容量为放入前i个物品(按i从小到大的顺序)的最大价值
int main()
{
cin >> T >> M;//T相当于背包总容量,M相当于物品个数
for (int i = 1; i <= M; i++)
cin >> tim[i] >> power[i];
for (int i = 1; i <= M; i++)
{
for (int j = tim[i]; j <= T; j++)
{
f[j] = max(f[j], f[j - tim[i]] + power[i]);
}
}
cout <<f[T] << "\n";
}
P1802 5倍经验日
本质上仍为0,1背包问题只不过当失败是时是仍旧有经验的所以要对递推式稍作修改
递推式:dp[i][j] = max(dp[i-1][j - yao[i]] + win[i], dp[i - 1][j] + lose[i])
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1005;
int n, x;
long long lose[maxn];
long long win[maxn];
long long yao[maxn];
long long dp[maxn][maxn];
int main()
{
cin >> n >> x;
for (int i = 1; i <= n; i++)
{
cin >> lose[i] >> win[i] >> yao[i];
}
for(int i=1;i<=n;i++)
for (int j = 0; j <= x; j++)
{
if (yao[i] <= j)
{
dp[i][j] = max(dp[i-1][j - yao[i]] + win[i], dp[i - 1][j] + lose[i]);
}
else
dp[i][j] = dp[i - 1][j] + lose[i];
}
cout << 5*dp[n][x] << "\n";
}
P2196 [NOIP1996 提高组] 挖地雷
f[i]:表示加入第i个节点时的最大地雷数
pre[i]:用来记录前驱结点
mp[i][j]用来记录地图上的两个节点是否相连
#include<iostream>
using namespace std;
int mp[25][25];
long long int weight[25];
long long int ans;
int pre[25];//前继结点
int flag=0;//记录最终到达结点
long long f[25];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>weight[i];
for(int i=1;i<=n-1;i++)
for(int j=i+1;j<=n;j++)
cin>>mp[i][j];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(mp[j][i]&&f[j]>f[i])
{
f[i]=f[j];
pre[i]=j;
}
}
f[i]+=weight[i];
if(f[i]>ans) {ans=f[i]; flag=i;}
}
int node[25];
int cnt=0;
int tmp=0;
node[0]=flag;
while(1)
{
tmp=pre[node[cnt]];
if(tmp==0) break;
node[++cnt]=tmp;
}
for(int i=cnt;i>=0;i--)
{
cout<<node[i]<<" ";
}
cout<<"\n";
cout<<ans<<"\n";
}
P4017 最大食物链计数
这是一道拓扑排序题,每次把入度为0的点i入栈,令dp[i]=1,然后不断更新和i相邻的点j的dp值,令dp[j]=dp[j]+dp[i],将j的入度-1,若入度为0则入栈,若入栈的点出度为0,则ans+=dp[j]。
#include<iostream>
#include<queue>
using namespace std;
int mp[5005][5005];
long long int n,m;
int chu[5005];
int ru[5005];
int dp[5005];
long long ans=0;
queue<int> qu;
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
mp[u][v]=1;
chu[u]++;
ru[v]++;
}
for(int i=1;i<=n;i++)
{
if(ru[i]==0)
{
qu.push(i);
dp[i]=1;
}
}
while(!qu.empty())
{
int temp=qu.front();
qu.pop();
for(int i=1;i<=n;i++)
{
if(mp[temp][i]==1)
{
dp[i]+=dp[temp];
dp[i]%=80112002;
ru[i]--;
if(ru[i]==0)
{
qu.push(i);
if(chu[i]==0)
{
ans+=dp[i];
ans%=80112002;
}
}
}
}
}
cout<<ans<<"\n";
}
P1002 [NOIP2002 普及组] 过河卒
一道简单的二维dp,dp[i][j]表示到达(i,j)时最大的路径数
注意当该位置是马所在的点或是马可以到达的点,那么dp[i][j]=0
如果不是则右左边和上边的dp值相加
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
long long dp[25][25];
int a, b;
int main()
{
cin >> n >> m >> a >> b;
for(int i=0;i<=n;i++)
for (int j = 0; j <= m; j++)
{
if (((i - a)*(i-a)+(j - b)*(j-b)) == 5||i==a&&j==b) dp[i][j] = 0;
else
{
if(i==0&&j==0) dp[0][0] = 1;
if(i == 0&&j!=0) dp[i][j] = dp[i][j-1];
if(j == 0&&i!=0) dp[i][j] = dp[i-1][j];
if(i!=0&&j!=0)
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
cout << dp[n][m]<< "\n";
}