1.区间DP:https://www.acwing.com/problem/content/323/
比较容易想到区间DP,转换一下均方差定义用记忆化搜索就可以了。
下面是AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 16;
int n, m = 8;
int s[N][N];
double f[N][N][N][N][N];
double X;
double get(int x1, int y1, int x2, int y2)
{double delta = s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1];delta = delta - X;return delta * delta;
}
double dp(int k, int x1, int y1, int x2, int y2)
{if (f[k][x1][y1][x2][y2] >= 0) return f[k][x1][y1][x2][y2];if (k == n) return f[k][x1][y1][x2][y2] = get(x1, y1, x2, y2); double t = 1e9; //初始化为无穷大for (int i = x1; i < x2; i ++ ) //横着切{t = min(t, dp(k + 1, x1, y1, i, y2) + get(i + 1, y1, x2, y2));t = min(t, dp(k + 1, i + 1, y1, x2, y2) + get(x1, y1, i, y2));}for (int i = y1; i < y2; i ++ ) //竖着切{t = min(t, dp(k + 1, x1, y1, x2, i) + get(x1, i + 1, x2, y2));t = min(t, dp(k + 1, x1, i + 1, x2, y2) + get(x1, y1, x2, i));}return f[k][x1][y1][x2][y2] = t;
}
int main()
{cin>>n;for (int i = 1; i <= m; i ++ )for (int j = 1; j <= m; j ++ )cin>>s[i][j];for (int i = 1; i <= m; i ++ )for (int j = 1; j <= m; j ++ )s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];memset(f, -1, sizeof f);X = (double) s[m][m] / n;printf("%.3lf\n", sqrt(dp(1, 1, 1, m, m) / n));return 0;
}
2.树形/换根DP:https://www.acwing.com/problem/content/1075/
我们不妨以1为根建树。
对于任意一个点X,他的最长距离就是max(d1[x],up[x]),其中d1是它向下的最长链,up是它向上的最长链,对于d1,我们只需要用儿子节点更新父节点即可,关键在于up[x]的求法:
首先,我们找到x的父亲k,up[x]=w[x][k]+maxx:这里w[x][k]表示x与k的边权,maxx就是父亲的up[k]和父亲的向下子链的max,这里注意,向下子链不可以穿过x,于是我们用d2[x]维护向下链的次大值,当我们发现最大值穿过时用次大值更新。
所以我们需要知道最大子链是否穿过x,我们只要在第一遍dfs维护root选max时的儿子节点即可。
那么我们怎么实现呢?我们发现这其实是用父节点更新儿子节点的过程,再来一遍DFS即可。
下面是AC代码:
#include<bits/stdc++.h>
using namespace std;
int n;
struct node{int dian;int zhi;
};
int d1[100010],d2[100010],up[100010];
int s1[100010],s2[100010];
vector<node> edge[100010];
void dfs1(int root,int fa){d1[root]=d2[root]=0;for(int i=0;i<edge[root].size();i++){int x=edge[root][i].dian;if(fa==x) continue;dfs1(x,root);if(d1[x]+edge[root][i].zhi>d1[root]){d2[root]=d1[root];d1[root]=d1[x]+edge[root][i].zhi;s1[root]=x;}else if(d1[x]+edge[root][i].zhi>d2[root]){d2[root]=d1[x]+edge[root][i].zhi;}}
}
void dfs2(int root,int fa){for(int i=0;i<edge[root].size();i++){int x=edge[root][i].dian;if(fa==x) continue;//更新儿子up[x]=edge[root][i].zhi;if(s1[root]==x) up[x]+=max(up[root],d2[root]);else up[x]+=max(up[root],d1[root]);dfs2(x,root);}
}
int main(){cin>>n;for(int i=1;i<=n-1;i++){int a,b,c;cin>>a>>b>>c;edge[a].push_back({b,c});edge[b].push_back({a,c});}dfs1(1,-1);dfs2(1,-1);int ans=0x3f3f3f3f;for(int i=1;i<=n;i++){ans=min(ans,max(up[i],d1[i]));}cout<<ans;
}