您的位置:首页 > 其它

sduacm16级寒假训练 动态规划(一)

2017-01-25 12:18 232 查看
https://vjudge.net/contest/148555

Password: acmlab2016

Hint: 均为模板题

A - 最长递增子序列

【题意】

求最长上升子序列(LIS)的长度。

【思路】

由于n<=1000,直接O(n^2)就可以

设f[i]表示以a[i]为结尾的最长上升子序列的长度

状态转移方程为f[i]=max{f[i],f[j]+1} (j

#include<cstdio>
#include<algorithm>
using namespace std;
const int Mx=1010;
int f[Mx];
int n,a[Mx];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
f[i]=1;
}
int ans=0;
for (int i=1;i<=n;i++)
for (int j=0;j<i;j++)
if (a[j]<a[i])
{
f[i]=max(f[i],f[j]+1);
ans=max(ans,f[i]);
}
printf("%d\n",ans);
return 0;
}


B - 最长公共子序列

【题意】

求最长公共子序列的长度。

【思路】

设两个字符串分别为s1和s2

f[i][j]表示s1的前i个字符和s2的前j个字符的最长公共子序列

如果s1[i] == s2[j]

f[i][j]=f[i-1][j-1]+1;

如果s1[i] != s2[j]

f[i][j]=max(f[i-1][j], f[i][j-1]);

【Code】

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Mx=1010;
int F[Mx][Mx];
char s1[Mx],s2[Mx];

int main()
{
while (~scanf("%s%s", s1+1, s2+1))
{
int n=strlen(s1+1),m=strlen(s2+1);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (s1[i]==s2[j]) F[i][j]=F[i-1][j-1]+1;
else F[i][j]=max(F[i-1][j],F[i][j-1]);
printf("%d\n", F
[m]);
}
return 0;
}


C - 01背包

【题意】

体积为V的背包最多能装价值为多少的物品

【思路】

裸的P01.

【Code】

#include<cstdio>
#include<algorithm>
int f[1010],v[1010],w[1010];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int m,n;
scanf("%d %d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&v[i]);
for (int i=1;i<=n;i++) scanf("%d",&w[i]);
for (int i=0;i<=m;i++) f[i]=0;
for (int i=1;i<=n;i++)
for (int j=m;j>=w[i];j--)
f[j]=std::max(f[j],f[j-w[i]]+v[i]);
printf("%d\n",f[m]);
}
}


D - 完全背包

【题意】

给定一个储钱罐的容量M,给定N种硬币的价值和重量,问是否能填满储钱罐,能填满则输出储钱罐内钱的最小值

【思路】

P02.

【Code】

#include<cstdio>
#include<algorithm>
int w[505],v[505],f[10050];
const int INF=0x3FFFFFFF;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m,e,t;
scanf("%d %d",&e,&t);
m=t-e;
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d %d",&v[i],&w[i]);
for (int i=0;i<=m;i++) f[i]=INF;
f[0]=0;
for (int i=1;i<=n;i++)
for(int j=w[i];j<=m;j++)
{
f[j]=std::min(f[j],f[j-w[i]]+v[i]);
//printf("f[%d,%d]=%d\n",i,j,f[j]);
}
if (f[m]!=INF) printf("The minimum amount of money in the piggy-bank is %d.\n",f[m]);
else printf("This is impossible.\n");
}
}


E - 多重背包

【题意】

给定6种价值的若干件物品,问是否能按价值平分物品.

【思路】

如果总价值为奇数,一定无解.

然后用的方法为判断性背包,不详细解释了.

【Code】

#include<cstdio>
#include<cstring>
int c[7];
bool f[200000];
int main()
{
int T=0;
while (++T)
{
int m=0;
for (int i=1;i<=6;i++)
{
scanf("%d",&c[i]);
m+=i*c[i];//一定注意这里是i*c[i]不是c[i]
}
if (m==0) break;
printf("Collection #%d:\n",T);
if (m%2==1)
{
printf("Can't be divided.\n\n");
continue;
}
m/=2;
memset(f,false,sizeof(f));
/*一开始用for(int i=1;i<=m;i++) f[i]=false;
不知道为什么会Wa..
有知道的可以告诉我一声*/
f[0]=true;
int cnt;
for (int i=1;i<=6;i++)
{
if (c[i]==0) continue;
for (int j=1;j<=c[i];j*=2)
{
cnt=i*j;
for (int k=m;k>=cnt;k--)
{
if (f[k-cnt]) f[k]=true;
//printf("f[%d]= %d.\n",k-cnt,f[k]?1:0);
}
c[i]-=j;
}
cnt=c[i]*i;
if (cnt)
{
for (int k=m;k>=cnt;k--)
{
if (f[k-cnt]) f[k]=true;
//printf("f[%d]= %d\n",k-cnt,f[k]?1:0);
}
}
}
if (f[m]) printf("Can be divided.\n\n");
else printf("Can't be divided.\n\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划 ACM