POJ 2228 Naptime
分析: 分两种情况
不是环形直接动态规划
是环形 加上第一个位置
然后用 一串来判断最优解
最后扫描 用一个 数把最大值存下
AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
const int maxn=3850;
using namespace std;
int n,m,map[maxn];
int dp[maxn][maxn];
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
dp[i][j]=0;
int ans=0;
for(int i=1;i<=n;i++)
scanf("%d",&map[i]);
for(int j=2;j<=m;j++){
int mx=0;
for(int i=j;i<=n;i++){
dp[i][j]=max(mx,dp[i-1][j-1]+map[i]);
mx=max(mx,dp[i-1][j-1]);
}
}
for(int i=m;i<=n;i++)
ans=max(ans,dp[i][m]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
dp[i][j]=0;
dp[2][2]=map[2];
for(int j=3;j<=m;j++){
int mx=0;
for(int i=j;i<=n;i++){
dp[i][j]=max(mx,dp[i-1][j-1]+map[i]);
mx=max(mx,dp[i-1][j-1]);
}
}
if(m>=2)
ans=max(ans,dp[n][m]+map[1]);
printf("%d\n",ans);
}
return 0;
}
POJ 2411 Mondriaan’s Dream
参考
状态压缩DP
这个题 就是要把横着放优先 这样才能保证最后一行不会出现竖着放的情况
将横着 按照 11 存 而 竖着的按照 0 1存
这样 最后一定覆盖满的状态 一定是
相邻的两行 相或 是1 相与 不是1 的个数是奇数(因为 如果是偶数的完全可以用横着来代替)
AC
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long dp[12][2050];
bool check(int s){
int ret=0;
while(s){
if(s&1)ret++;
else{
if(ret&1)
return 0;
ret =0;
}
s>>=1;
}
if(ret&1)return 0;
return 1;
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
if(n==0&&m==0) break;
int tot=(1<<m);
memset(dp,0,sizeof(dp));
for(int i=0;i<tot;i++)
if(check(i)) dp[1][i]=1;
for(int i=1;i<n;i++)
for(int j=0;j<tot;j++)
if(dp[i][j]){
for(int k=0;k<tot;k++)
if( (j|k)==tot-1&& check(j&k) )
dp[i+1][k]+=dp[i][j];
}
printf("%I64d\n",dp[n][tot-1]);
}
return 0;
}
URAL 1018 Binary Apple Tree
树形DP
状态转移方程:f[i][j]=max(ans[leftchild][k]+f[rightchild][j-k-1])+value
就是 按照状态转移方程求出最大苹果树
如果没有标记 就记录左 儿子,标记了就记录右儿子
最后输出尾值就是最大值
AC代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn =101;
struct edge{
int t;
int next;
int v;
}a[2*maxn];
struct point{
int l,r;
int v;
}b[maxn];
int n,m;
int tot=0,last[maxn],f[maxn][maxn];
bool vis [maxn];
void add(int from,int to,int value)
{
a[++tot].t=to;
a[tot].v=value;
a[tot].next=last[from];
last[from]=tot;
}
void build(int now)
{
vis[now]=true;
for(int i=last[now];i;i=a[i].next)
{
if(!vis[a[i].t])
{
if(!b[now].l)//没有的话 记录左儿子
b[now].l=a[i].t;
else b[now].r=a[i].t;//否则记录右儿子<二叉树>
b[a[i].t].v=a[i].v;
build(a[i].t);
}
}
}
int treedp(int now,int rest)
{
if(!now || !rest) return 0;
if(f[now][rest]) return f[now][rest];
for(int i=0;i<rest;i++)
f[now][rest]=max(f[now][rest],treedp(b[now].l,i)+treedp(b[now].r,rest-i-1));
f[now][rest]+=b[now].v;
return f[now][rest];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
int A,B,C;
scanf("%d%d%d",&A,&B,&C);
add(A,B,C);
add(B,A,C);
}
build(1);//建树
printf("%d\n",treedp(1,m+1));
return 0;
}