详细算法见:https://user.qzone.qq.com/50222268/blog/1503921896
1.题目:https://www.luogu.org/problemnew/show/P2014#sub
如何将普通树变成兄弟二叉树:
无父节点的节点为 n+1
for (int i=1; i<=n; ++i) {
int a, b;
cin >> a >> b;
if (a == 0) a = n + 1;
score[i] = b;
brother[i] = child[a];//i节点的兄弟为其父节点a的孩子
child[a] = i;
}
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct node
{
int wei,l,r;
};
const int maxSize=300;
int n,m;
int vis[maxSize+5][maxSize+5],f[maxSize+5][maxSize+5];
node N[maxSize+5];
void dfs(int x,int y)
{
int i,j;
if (vis[x][y]==1)//防止重复搜
return ;
vis[x][y]=1;
if (x==0 || y==0)
return ;
dfs(N[x].r,y); //不选x节点
f[x][y]=f[N[x].r][y];
for (i=0;i<y;i++)//选x节点
{
dfs(N[x].l,i); //孩子节点选i个
dfs(N[x].r,y-i-1); //兄弟节点选y-i-1个
f[x][y]=max(f[x][y],f[N[x].l][i]+f[N[x].r][y-i-1]+N[x].wei);
}
}
int main()
{
int i,x,y,ans;
freopen("a.txt","r",stdin);
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
if (x==0)
x=n+1;
N[i].wei=y;
N[i].r=N[x].l;
N[x].l=i;
}
for (i=1;i<=n;i++)
dfs(i,m);//从根节点搜起
ans=0;
for (i=1;i<=n;i++)
ans=max(ans,f[i][m]);
printf("%d\n",ans);
return 0;
}
2.题目:https://www.luogu.org/problemnew/show/P2015#sub
此题要注意把边权化点权
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
struct node
{
int wei,y;
};
struct node1
{
int l,r,wei;
};
const int maxSize=100;
int n,q;
int vis[maxSize+5],visit[maxSize+5][maxSize+5],f[maxSize+5][maxSize+5];
node1 a[maxSize+5];
vector <node> N[maxSize+5];
void read(int x)
{
int i;
node n1;
for (i=0;i<N[x].size();i++)
{
n1=N[x][i];
if (vis[n1.y]==1)
continue;
a[n1.y].wei=n1.wei;//边权变成点权
if (a[x].l==0)
a[x].l=n1.y;
else
a[x].r=n1.y;
vis[n1.y]=1;
read(n1.y);
vis[n1.y]=0;
}
}
void dfs(int x,int q)
{
int i;
node n1;
if (visit[x][q]==1)
return ;
visit[x][q]=1;
if (x==0 || q==0)
return ;
for (i=0;i<q;i++)
{
dfs(a[x].l,i);
dfs(a[x].r,q-i-1);
f[x][q]=max(f[x][q],f[a[x].l][i]+f[a[x].r][q-i-1]+a[x].wei);
}
}
int main()
{
int i,x,y,z;
node n1;
freopen("a.txt","r",stdin);
scanf("%d%d",&n,&q);
for (i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
n1.y=y; n1.wei=z;
N[x].push_back(n1);
n1.y=x;
N[y].push_back(n1);
}
memset(vis,0,sizeof(vis));
memset(visit,0,sizeof(visit));
vis[1]=1;
read(1);
// for (i=1;i<=n;i++)
// printf("%d %d %d\n",a[i].l,a[i].r,a[i].wei);
dfs(1,q+1);
printf("%d\n",f[1][q+1]);
return 0;
}
3.题目:https://www.luogu.org/problemnew/show/P1352#sub
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
struct node
{
int y,wei;//wei指y的权重
};
const int maxSize=6000;
vector <node> N[maxSize+5];
int n;
int a[maxSize+5],ru[maxSize+5],vis[maxSize+5],f[maxSize+5][2];
//f 0去 1不去
void dfs(int x)
{
int i,f1=0,f0=0;
node n1;
for (i=0;i<N[x].size();i++)
{
n1=N[x][i];
if (vis[n1.y]==1)
continue;
vis[n1.y]=1;
dfs(n1.y);
vis[n1.y]=0;
f0+=f[n1.y][1];
f1+=max(f[n1.y][0],f[n1.y][1]);
}
f[x][0]=max(f[x][0],f0+a[x]);
f[x][1]=max(f[x][1],f1);
}
int main()
{
int i,x,y,gen;
node n1;
freopen("a.txt","r",stdin);
scanf("%d",&n);
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
memset(ru,0,sizeof(ru));
for (i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
n1.y=x; n1.wei=a[x];
N[y].push_back(n1);
ru[x]++;
}
for (i=1;i<=n;i++)
{
if (ru[i]==0)
{
gen=i;
break;
}
}
memset(vis,0,sizeof(vis));
dfs(gen);
printf("%d\n",max(f[gen][0],f[gen][1]));
return 0;
}
4.完美服务器
gfoj---course---动态规划2
注意状态转移方程可以化简
写程序时方程不能特判!!!
原因:
1,此方程是递推出来的,所以不能特判
2,若不满足则直接上maxValue,此处maxValue不能过大。。。
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int maxSize=10000,maxValue=1000000;
vector <int> N[maxSize+5];
int vis[maxSize+5],f[maxSize+5][3];
void dfs(int x)
{
int i,y;
for (i=0;i<N[x].size();i++)
{
y=N[x][i];
if (vis[y]==1)
continue;
vis[y]=1;
dfs(y);
vis[y]=0;
f[x][0]+=min(f[y][1],f[y][0]);
f[x][1]+=f[y][2];
}
for (i=0;i<N[x].size();i++)
{
y=N[x][i];
if (vis[y]==1)
continue;
f[x][2]=min(f[x][2],f[y][0]+f[x][1]-f[y][2]);
}
}
int main()
{
int i,n,x,y;
freopen("a.txt","r",stdin);
while (1)
{
scanf("%d",&n);
if (n==-1)
break;
if (n==0)
continue;
for (i=1;i<=n;i++)
N[i].clear();
for (i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
N[x].push_back(y);
N[y].push_back(x);
}
memset(vis,0,sizeof(vis));
for (i=1;i<=n;i++)
{
f[i][0]=1;
f[i][1]=0;
f[i][2]=maxValue;
}
vis[1]=1;
dfs(1);
printf("%d\n",min(f[1][0],f[1][2]));
}
return 0;
}
5.寻宝:
https://blog.csdn.net/scutbenson/article/details/81738322
6.行动!行动!