P1352 没有上司的舞会
/*
没有上司的舞会
P1352
https://www.luogu.org/problem/P1352
题意:有一场舞会,每一个人都有一个快乐值,但不能和上司同时出现在舞会中,问这个舞会的快乐值最大为多少
解法:
树状DP
*/
#include <bits/stdc++.h>
using namespace std;
#define maxn 100000
struct node{
int u,v;
int next;
}edge[maxn];
int head[maxn],cnt;
int dp[maxn][2];
int a[maxn];
void init(){
memset(head,-1,sizeof head);
cnt=0;
}
void add(int u,int v){
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int u,int fa){
dp[u][0]=0;
dp[u][1]=a[u];
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
if(v!=fa){
dfs(v, u);
dp[u][0]+=max(dp[v][0],dp[v][1]);
dp[u][1]+=dp[v][0];
}
}
}
int main(){
int n,u,v;
cin>>n;
init();
for(int i=1;i<=n;i++) cin>>a[i];
while(cin>>u>>v&&u+v){
add(u,v);
add(v,u);
}
dfs(1,-1);
cout<<max(dp[1][0],dp[1][1])<<endl;
return 0;
}
The more, The Better
/*
The more, The Better
HDU - 1561
https://cn.vjudge.net/problem/HDU-1561
题意:每一个城市都有一定的宝物,允许攻克m个城堡,有些城堡不能直接攻克,要攻克它先必须攻克指定的城堡,问最多可以得到多少宝物
解法:
树状DP+01背包
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 1000
int dp[maxn][maxn];
int f[maxn][maxn];
int as[maxn];
struct node{
int u,v;
int next;
}edge[maxn];
int head[maxn];
int cnt;
int n,m,a,b;
void init(){
memset(head,-1,sizeof head);
memset(dp,0,sizeof dp);
memset(f,0,sizeof f);
memset(as,0,sizeof as);
cnt=0;
}
void add(int u,int v){
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int u){
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
dfs(v);
for(int k=m;k>=0;k--){
for(int j=0;j<=k;j++){
f[u][k]=max(f[u][k],f[u][k-j]+dp[v][j]);
}
}
}
for(int i=1;i<=m+1;i++)
dp[u][i]=f[u][i-1]+as[u];
}
int main(){
while(cin>>n>>m&&n+m){
init();
for(int i=1;i<=n;i++){
cin>>a>>b;
as[i]=b;
add(a,i);
}
dfs(0);
printf("%d\n",dp[0][m+1]);
}
return 0;
}
Binary Apple Tree
解法一:
/*
Binary Apple Tree
URAL - 1018
https://cn.vjudge.net/problem/URAL-1018
题面:有一棵二叉苹果树,每个节点都有苹果,现在让你保留下来m条枝头,问最多可以剩余多少个苹果
解法:
树状DP + 01背包
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 1000
int f[maxn][maxn];
int as[maxn];
struct node{
int u,v,w;
int next;
}edge[maxn];
int head[maxn];
int cnt;
int n,m;
void init(){
memset(head,-1,sizeof head);
memset(f,0,sizeof f);
cnt=0;
}
int max(int a,int b){
if(a>b) return a;
return b;
}
void add(int u,int v,int w){
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int u,int fa){
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
if(v!=fa){
dfs(v,u);
for(int k=m;k>=0;k--){
for(int j=1;j<=k;j++){
if(f[u][k]<f[u][k-j]+f[v][j-1]+edge[i].w)
f[u][k]=f[u][k-j]+f[v][j-1]+edge[i].w;
}
}
}
}
}
int main(){
int a,b,c;
while(cin>>n>>m){
init();
for(int i=1;i<n;i++){
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
dfs(1,1);
printf("%d\n",f[1][m]);
}
return 0;
}
解法二:
/*
Binary Apple Tree
URAL - 1018
https://cn.vjudge.net/problem/URAL-1018
题面:有一棵二叉苹果树,每个节点都有苹果,现在让你保留下来m条枝头,问最多可以剩余多少个苹果
解法:
dfs + 记忆化 + 枚举
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 1000
int dp[maxn][maxn];
int f[maxn][maxn];
int as[maxn];
struct node{
int u,v,w;
int next;
}edge[maxn];
int head[maxn];
int cnt;
int n,m;
void init(){
memset(head,-1,sizeof head);
memset(dp,0,sizeof dp);
cnt=0;
}
int max(int a,int b){
if(a>b) return a;
return b;
}
void add(int u,int v,int w){
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int u,int fa){
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
if(v!=fa){
as[v]=edge[i].w;
dfs(v,u);
for(int k=m;k>=0;k--){
for(int j=0;j<=k;j++){
f[u][k]=max(f[u][k],f[u][k-j]+dp[v][j]);
}
}
}
}
for(int i=1;i<=m+1;i++)
dp[u][i]=f[u][i-1]+as[u];
}
int main(){
int a,b,c;
while(cin>>n>>m){
init();
for(int i=1;i<n;i++){
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
dfs(1,1);
printf("%d\n",dp[1][m+1]);
}
return 0;
}
Strategic game
/*
Strategic game
POJ - 1463
https://cn.vjudge.net/problem/POJ-1463
题面:最小点覆盖
解法: 树状DP
*/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
#define maxn 100000
struct node{
int u,v;
int next;
}edge[maxn];
int head[maxn];
int dp[maxn][2];
int cnt;
void init(){
memset(head,-1,sizeof head);
memset(dp,0,sizeof dp);
cnt=0;
}
void add(int u,int v){
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int u,int fa){
//cout<<u<<endl;
dp[u][0]=0;
dp[u][1]=1;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
if(v!=fa){
dfs(v,u);
dp[u][0]+=dp[v][1];
dp[u][1]+=min(dp[v][0],dp[v][1]);
}
}
}
int main(){
int n,m,k,a;
while(cin>>n){
init();
for(int i=0;i<n;i++){
scanf("%d:(%d)", &m, &k);
for(int i=0;i<k;i++){
cin>>a;
add(m,a);
add(a,m);
}
}
dfs(0,0);
cout<<min(dp[0][0],dp[0][1])<<endl;
}
return 0;
}
Cell Phone Network
/*
Cell Phone Network
POJ - 3659
https://cn.vjudge.net/problem/POJ-3659
题面:最小支配集
解法: 树状DP
*/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
#define maxn 500000
#define INF 0x3f3f3f3f
struct node{
int u,v;
int next;
}edge[maxn];
int head[maxn];
int dp[maxn][3];
int cnt;
void init(){
memset(head,-1,sizeof head);
memset(dp,0,sizeof dp);
cnt=0;
}
void add(int u,int v){
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int u,int fa){
dp[u][0]=1;
dp[u][1]=0;
dp[u][2]=0;
int sum=0,inc=INF;
bool judge=false;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
if(v!=fa){
dfs(v,u);
dp[u][0]+=min(dp[v][0],min(dp[v][1],dp[v][2]));
if(dp[v][0]<=dp[v][1]){
sum+=dp[v][0];
judge=true;
}else{
sum+=dp[v][1];
inc=min(inc,dp[v][0]-dp[v][1]);
}
if(dp[v][1]!=INF&&dp[u][2]!=INF) dp[u][2]+=dp[v][1];
else dp[u][2]=INF;
dp[u][1]+=min(dp[v][0],dp[v][1]);
}
}
if(inc==INF&&!judge) dp[u][1]=INF;
else {
dp[u][1]=sum;
if(!judge) dp[u][1]+=inc;
}
}
int main(){
int n,u,v;
while(cin>>n){
init();
for(int i=1;i<n;i++){
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs(1,1);
cout<<min(dp[1][0],min(dp[1][1],dp[1][2]+1))<<endl;
}
return 0;
}