万能DFS——CF1292C Xenon's Attack on the Gangs 题解

来看一下题目链接:https://www.cnblogs.com/liuchanglc/p/12677786.html

大家在看题解前一定要先看题目哟。

下面我就要开始咯!

题意:给n个结点,n-1条无向边。即一棵树。我们需要给这n-1条边赋上0~ n-2不重复的值。mex(u,v)表示从结点u到结点v经过的边权值中没有出现的最小非负整数。计算下面等式的最大值:

 

先来几个定义:

我们用f[i][j]表示从i开始,从j结束,将i到j之间所有的m条边赋值成0到m-1所得到的最大价值

用g[i][j]表示在i号节点作为根节点的情况下,以j为根节点的字数的大小

用pa[i][j]表示在i号节点作为根节点的情况下,j节点的父亲节点。

然后再来张图。

 下面给出状态转移方程。

f[u][v]=max(f[u,pa[u][v]],f[v,pa[v][u]])+g[u][v]*g[v][u]

什么意思呢,我们还是拿图来说

我们假设pa[v][u]和pa[u][v]之间的权值已经确定,那么下一个权值我们可以选择加在(u,pa[v][u])上,也可以选择加在(v,pa[u][v])上

 如果加在(u,pa[v][u])上,那么增大的价值就是g[u][v]*g[v][u],还要加上原来就有的f[u,pa[u][v]]

 如果加在(v,pa[u][v])上,那么增大的价值就是g[u][v]*g[v][u],还要加上原来就有的f[v,pa[v][u]]

实际上这两种情况增大的价值都是一样的,我们只需要在f[u,pa[u][v]]和f[v,pa[v][u]]中取最大值就可以了

g、pa数组我们可以预处理得到,f数组我们枚举取最大值就可以了

这道题也要开long long否则会爆掉

注:图片引用自https://www.cnblogs.com/liuchanglc/ 的博客

下面是代码:

呵呵,再往下看看

先看完整版:

我精简过的,只有38行。

这个是50行的
这个我也不知道是啥
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=3005;
 4 typedef long long ll;
 5 struct node{
 6     ll from,to,next;
 7 }e[maxn*2];ll head[maxn],cnt=1;
 8 void add(ll xx,ll yy){
 9     e[cnt].from=xx;e[cnt].to=yy;e[cnt].next=head[xx];head[xx]=cnt++;
10 }
11 ll pa[maxn][maxn],f[maxn][maxn],g[maxn][maxn],root=1;
12 void DFS(ll now,ll fa){
13     g[root][now]=1;
14     for(ll i=head[now];i!=-1;i=e[i].next){
15         ll u=e[i].to;if(u==fa) continue;
16         pa[root][u]=now;DFS(u,now);
17         g[root][now]+=g[root][u];
18     }
19 }
20 ll jiejue(ll u,ll v){
21     if(u==v) return 0;if(f[u][v]) return f[u][v];
22     return f[u][v]=max(jiejue(u,pa[u][v]),jiejue(v,pa[v][u]))+g[u][v]*g[v][u];
23 }
24 int main(){
25     //freopen("a.in","r",stdin);
26     ll n;scanf("%lld",&n);
27     memset(head,-1,sizeof(head));
28     for(ll i=1;i<n;i++){
29         ll xx,yy;scanf("%lld%lld",&xx,&yy);
30         add(xx,yy);add(yy,xx);
31     }
32     for(ll i=1;i<=n;i++){
33         root=i;DFS(i,-1);
34     }ll answer=-1;
35     for(ll i=1;i<=n;i++)for(ll j=1;j<=n;j++)answer=max(jiejue(i,j),answer);
36     printf("%lld\n",answer);
37     return 0;
38 }
38行

然后是DFS代码

1 void DFS(ll now,ll fa){
2     g[root][now]=1;
3     for(ll i=head[now];i!=-1;i=e[i].next){
4         ll u=e[i].to;
5         if(u==fa) continue;
6         pa[root][u]=now;DFS(u,now);
7         g[root][now]+=g[root][u];
8     }
9 }
View Code

最后是解决部分的代码

1 ll jiejue(ll u,ll v){
2     if(u==v) return 0;
3     if(f[u][v]) return f[u][v];
4     return f[u][v]=max(jiejue(u,pa[u][v]),jiejue(v,pa[v][u]))+g[u][v]*g[v][u];
5 }
View Code

这道题主要在于思路吧。

猜你喜欢

转载自www.cnblogs.com/DZN2004/p/12678837.html
今日推荐