题目链接:https://zhixincode.com/contest/14/problem/D?problem_id=206

样例输入 1 

5 5
1 2 1
1 3 1
2 4 1
2 5 1
1 5 1

样例输出 1

20

样例输入 2 

5 10
1 2 1
1 3 2
1 4 3
1 5 4
2 3 5
2 4 6
2 5 7
3 4 8
3 5 9
4 5 10

样例输出 2

146

题解:

首先,删除一条边不可能使得任意两座城市的最短距离变得更近,所以尽可能地多删除边不会有任何坏处,因此最后得到的道路系统应该就是一棵树。

(吉老师表示,这道题是生成树上状压dp的经典套路。我这只蒟蒻听得一愣一愣的,感觉自己dp确实太薄弱了……)

jls表示套路是:用 $dp[i][S]$ 来表示一棵子树的某些属性,这棵子树的所有节点组成点集 $S$,并且该子树以 $i$ 节点为根。

首先将要计算的 $\sum_{i=1}^{n} \sum_{j=i+1}^{n} d(i,j)$ 转变成另一种计算方法,考虑一条边 $(u_i,v_i,w_i)$ 对这个答案的贡献;

考虑到一棵树上任意两个点间的路径都是唯一的,所以最短路就是唯一的那一条路径。因此一条边 $(u_i,v_i,w_i)$ 在 $\sum_{i=1}^{n} \sum_{j=i+1}^{n} d(i,j)$ 中被计算几次,就等于以这条边两端的两个子树内节点数的乘积。我们把这个值叫做这条边的贡献。

然后用 $dp[i][S]$ 表示在点集 $S$ 上构造了一棵根为 $i$ 的生成树,它的所有边的贡献之和是最大的。我们不需要关心树的具体结构,我们只要知道在点集 $S$ 上可以搞出一棵生成树,这棵树的复杂程度是最大就好了。

那么如何进行转移呢?很容易想到需要枚举子集,我们可以枚举 $S$ 的真子集 $T$,显然由于 $|T|<|S|$,所以对于任意的 $j \in T$,$dp[j][T]$ 肯定已经被计算好了;同样的,对于集合 $S-T$,对于任意的 $i \in S-T$,$dp[i][S-T]$ 肯定也是计算好了的。除非这是一个非法状态,换句话说即在原图上 $T$ 或者 $S-T$ 是不连通的。

那么,状态转移方程即:对于在原图中存在的 $\forall edge(i,j)$,其中 $i \in S-T, j \in T$,有 $dp[i][S] = max(dp[i][S],dp[j][T]+dp[i][S-T]+ w(i,j) \cdot |T| \cdot |n-T|)$。(这里有一个易错的点是误认为是 $dp[j][T]+dp[i][S-T]+ w(i,j) \cdot |T| \cdot |S-T|$,错误的理由是 $S$ 并不是全集 $V$)

注:这个状压dp涉及到枚举子集的运算, x = x & (x-) 是把 $x$ 二进制下最靠右的第一个 $1$ 变为 $0$, for(int t=s;t;t=(t-)&s){} 则可以枚举 $s$ 的子集 $t$,而对于 $s$ 的一个子集 $t$ 求其补集 $s_t$ 则可以用 s_t = s ^ t 。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=; int n,m;
ll mp[maxn][maxn];
ll dp[maxn][<<maxn];
vector<int> poi[<<maxn]; int main()
{
ios::sync_with_stdio();
cin.tie(), cout.tie(); cin>>n>>m;
for(int i=,u,v,w;i<=m;i++)
{
cin>>u>>v>>w;
mp[u][v]=mp[v][u]=(ll)w;
} memset(dp,-,sizeof(dp));
for(int s=;s<(<<n);s++)
{
for(int i=;i<=n;i++) if(s&(<<(i-))) poi[s].push_back(i);
if(poi[s].size()==) dp[poi[s].front()][s]=; //对于只有一个点的状态进行初始化
} for(int s=;s<(<<n);s++)
{
for(int t=(s-)&s;t;t=(t-)&s)
{
if(dp[poi[t].front()][t]==-) continue; //在原图上集合T不连通
if(dp[poi[s-t].front()][s-t]==-) continue; //在原图上集合S-T不连通
for(auto i:poi[s-t])
{
for(auto j:poi[t])
{
if(!mp[i][j]) continue;
ll T=poi[t].size();
dp[i][s]=max(dp[i][s],dp[j][t]+dp[i][s-t]+T*(n-T)*mp[i][j]);
}
}
}
} ll ans=;
for(int i=;i<=n;i++) ans=max(ans,dp[i][(<<n)-]);
cout<<ans<<endl;
}

CCPC-Wannafly Winter Camp Day3 Div1 - 精简改良 - [生成树][状压DP]的更多相关文章

  1. 【CCPC-Wannafly Winter Camp Day3 (Div1) D】精简改良(状压DP)

    点此看题面 大致题意: 给你一张图,定义\(dis(i,j)\)为\(i\)与\(j\)的最短距离,现要求删去若干条边,使得图仍然联通,且\(\sum_{i=1}^n\sum_{j=i+1}^ndis ...

  2. 2020 CCPC Wannafly Winter Camp Day1 C. 染色图

    2020 CCPC Wannafly Winter Camp Day1 C. 染色图 定义一张无向图 G=⟨V,E⟩ 是 k 可染色的当且仅当存在函数 f:V↦{1,2,⋯,k} 满足对于 G 中的任 ...

  3. Wannafly Winter Camp Day8(Div1,onsite) E题 Souls-like Game 线段树 矩阵乘法

    目录 Catalog Solution: (有任何问题欢迎留言或私聊 && 欢迎交流讨论哦 Catalog @ Problem:传送门  Portal  原题目描述在最下面.  简单的 ...

  4. CCPC-Wannafly Winter Camp Day3 Div1 - 石头剪刀布 - [带权并查集]

    题目链接:https://zhixincode.com/contest/14/problem/I?problem_id=211 样例输入 1  3 5 2 1 1 2 1 2 1 1 2 3 2 1 ...

  5. CCPC-Wannafly Winter Camp Day3 Div1 - 排列

    题目链接:https://zhixincode.com/contest/14/problem/A?problem_id=203 time limit per test: 1 secondmemory ...

  6. 【CCPC-Wannafly Winter Camp Day3 (Div1) G】排列(水题)

    点此看题面 大致题意:已知 \(p\)为\(n\)的一个排列,定义\(A(p)_i=min_{j=1}^ip_j\),若用\(q_i\)表示\(p\)第\(i\)小的前缀的长度(以值为第一关键字,下标 ...

  7. 【CCPC-Wannafly Winter Camp Day3 (Div1) F】小清新数论(莫比乌斯反演+杜教筛)

    点此看题面 大致题意: 让你求出\(\sum_{i=1}^n\sum_{j=1}^n\mu(gcd(i,j))\). 莫比乌斯反演 这种题目,一看就是莫比乌斯反演啊!(连莫比乌斯函数都有) 关于莫比乌 ...

  8. 【CCPC-Wannafly Winter Camp Day3 (Div1) I】石头剪刀布(按秩合并并查集)

    点此看题面 大致题意: 有\(n\)个人,第\(i\)个人坐在编号为\(i\)的座位上,每个人等概率有石头.剪刀.布中的一张卡片.有两种操作:第一种是第\(y\)个人挑战第\(x\)个人,如果胜利则\ ...

  9. CCPC Wannafly Winter Camp Div2 部分题解

    Day 1, Div 2, Prob. B - 吃豆豆 题目大意 wls有一个\(n\)行\(m\)列的棋盘,对于第\(i\)行第\(j\)列的格子,每过\(T[i][j]\)秒会在上面出现一个糖果, ...

随机推荐

  1. ios中输入框的父类--文本框,DataPick,pickerview

    父控制器 #import <UIKit/UIKit.h> #import "ScrollViewExt.h" @interface BaseKeyBoardCtrl : ...

  2. Database数据库切片模式

    数据库切片模式关注的实现水平伸缩.切分是从单个数据库到平分数据访问两个或更多数据库切片.每个切片有和原始数据库相同的Schema.大多数据分布在每个切片每一行.从切片合并起来的数据和原始数据库一样.切 ...

  3. IDEA使用笔记(七)——编辑器最大个数的设置

    我想一定有许多人和我一样在使用IDEA的时候,打开了许多的编辑器选项卡,但是打开的数量是有限的,我们想打开更多的页面,并且希望控制当再次达到大限的时候能关闭那些我们最久没有看的文件! 好吧!看下面的配 ...

  4. 【Android】Android输入子系统

    成鹏致远 | lcw.cnblogs.com | 2013-10-25 Linux输入子系统回顾 1:为什么要回顾linux输入子系统?这个问题后面自然就知道了 1.linux输入子系统设备是基于平台 ...

  5. java框架篇---struts之文件上传和下载

    Struts2文件上传 Struts 2框架提供了内置支持处理文件上传使用基于HTML表单的文件上传.上传一个文件时,它通常会被存储在一个临时目录中,他们应该由Action类进行处理或移动到一个永久的 ...

  6. 【iCore4 双核心板_FPGA】例程八:乘法器实验——乘法器使用

    实验现象: 程序运行时,绿色led闪烁(目前,具体的乘法器调用请参考iCore3乘法器例程) 核心代码: module multiplier_ctrl( input clk_25m, input rs ...

  7. android开发(48) Android Snackbar 的使用

    Snackbar 类似toast,用于向 用户展示信息,和用户交互,它能够显示一个 按钮 获得用户的操作.它的特点如下: 作为android.support.design.widget.Coordin ...

  8. Python内置类型——list

    list(列表)是Python内置的可变序列(Sequence)类型,list的对象的方法也都是就地(in-place)更改调用这些方法的列表对象, List的一些细节 可以直接为list的某个下标赋 ...

  9. 转:【WebView的cookie机制 】轻松搞定WebView cookie同步问题

    原文链接:http://blog.csdn.net/fengyuzhengfan/article/details/51517622 在进行APP+H5混合开发的时候,一些功能是用native方法实现的 ...

  10. python 爬虫练习

    bs去除特定标签. # url import easygui as g import urllib.request from bs4 import BeautifulSoup import os im ...