题解 Connect
各种骗分无果,特殊性质还手残写挂了……
首先完全图上直接输出边权 \(\times (n-2)\) 就行了,然而我脑残乘的 \(n-1\)
看数据范围肯定是状压,但是压边肯定炸了,考虑压点
因为1到n路径唯一,最终的图可以看作一条链上挂着数个连通块
根据题解,我们试着从这个方向下手
那这里状压的时候我们既要考虑这条链,又要考虑连通块
发现只有链上的最后一个元素有用,所以令 \(dp[s][k]\) 为已选的点集为 \(s\) ,链的末端为k时的最大边权和
考虑转移,发现我们可以向链的末端挂上一个任意大小的联通块
所以直接暴力 \(O(n^23^n)\) 枚举转移,发现T了
于是大力卡常,预处理优化到 \(O(\frac{n^2}{4}3^n)\) ,发现过了,然后就没有了
其实还可以优化,考虑把「挂任意大小的联通块」拆成「挂一个元素」和「在当前链的末端挂一个连通块,但不改变链的末端元素」两种情况
然后就可以分开转移,可以康康战神代码
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define reg register int
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
ll sum;
namespace force{
ll ans;
int head[N], size;
bool vis[N], use[N], fa[N];
struct edge{int from, to, next, val;}e[N<<1];
inline void add(int s, int t, int w) {edge* k=&e[++size]; k->from=s; k->to=t; k->val=w; k->next=head[s]; head[s]=size;}
inline bool operator < (edge a, edge b) {return a.val<b.val;}
inline int find(int p) {return fa[p]==p?p:fa[p]=find(fa[p]);}
bool dfs(int u) {
vis[u]=1;
bool yes=0;
for (int i=head[u],v; i; i=e[i].next) {
v = e[i].to;
if (!vis[v]) {
if (dfs(v)) yes=1;
}
}
if (yes) {
use[u]=1;
for (int i=head[u]; i; i=e[i].next)
use[e[i].to]=1;
}
return (u==n)||yes;
}
void kruskal() {
sort(e+1, e+size+1);
for (int i=1,f1,f2; i<=size; ++i) {
f1=find(e[i].from), f2=find(e[i].to);
if (f1!=f2) {
ans+=e[i].val;
}
else if (!(use[e[i].from]&&use[e[i].to])) ans+=e[i].val;
}
}
void solve() {
bool same=1; int lst=0;
for (int i=1,u,v,w; i<=m; ++i) {
u=read(); v=read(); w=read(); sum+=w;
add(u, v, w); add(v, u, w);
if (lst&&w!=lst) same=0;
else lst=w;
}
dfs(1);
if (same && m>=n*(n-1)/2) {printf("%lld\n", 1ll*lst*(n-2)); exit(0);}
//for (int i=1; i<=n; ++i) cout<<use[i]<<' '; cout<<endl;
kruskal();
printf("%lld\n", sum-ans);
exit(0);
}
}
namespace task{
ll dp[1<<16][16], sum[1<<16][16], tot;
int mp[16][16], lg[1<<16];
void solve() {
for (int i=1,u,v; i<=m; ++i) {
u=read()-1; v=read()-1;
tot+=(mp[u][v]=mp[v][u]=read());
}
int lim=1<<n; ll tem;
for (int i=0; i<n; ++i) lg[1<<i]=i;
for (reg s=1; s<lim; ++s) {
tem=0;
for (reg i=0; i<n; ++i) if (s&(1<<i))
for (reg j=i+1; j<n; ++j) if (s&(1<<j))
tem+=mp[i][j];
if (s&1) dp[s][0]=sum[s][0]=tem;
else for (reg i=0; i<n; ++i) if (s&(1<<i)) sum[s][i]=tem;
}
for (reg s=1,s2; s<lim; ++s) {
if (!(s&1)) continue;
for (reg s0=s2=(~s)&(lim-1); s0; s0=(s0-1)&s2)
for (reg i=s; i; i-=i&-i)
for (reg j=s0; j; j-=j&-j)
dp[s|s0][lg[j&-j]] = max(dp[s|s0][lg[j&-j]], dp[s][lg[i&-i]]+sum[s0][lg[j&-j]]+mp[lg[i&-i]][lg[j&-j]]);
#if 0
for (reg i=0; i<n; ++i) if (s&(1<<i))
for (reg j=0; j<n; ++j) if (s0&(1<<j)&&mp[i][j]) {
//if (dp[s][i]+sum[s0][j]+mp[i][j] > dp[s|s0][j]) cout<<"new ans"<<endl;
dp[s|s0][j] = max(dp[s|s0][j], dp[s][i]+sum[s0][j]+mp[i][j]);
//cout<<"upd "<<bitset<15>(s)<<' '<<bitset<15>(s0)<<' '<<i<<' '<<j<<' '<<dp[s][i]<<' '<<sum[s0][j]<<' '<<mp[i][j]<<endl;
}
#endif
}
//cout<<"dp: "<<dp[lim-1][n-1]<<endl;
printf("%lld\n", tot-dp[lim-1][n-1]);
exit(0);
}
}
signed main()
{
n=read(); m=read();
task::solve();
return 0;
}
题解 Connect的更多相关文章
- LeetCode OJ 题解
博客搬至blog.csgrandeur.com,cnblogs不再更新. 新的题解会更新在新博客:http://blog.csgrandeur.com/2014/01/15/LeetCode-OJ-S ...
- Connect the Cities(prime)
Connect the Cities Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) ...
- usaco training 4.1.3 fence6 题解
Fence Loops题解 The fences that surround Farmer Brown's collection of pastures have gotten out of cont ...
- usaco 2002 月赛 Fiber Communications 题解
Description Farmer John wants to connect his N (1 <= N <= 1,000) barns (numbered 1..N) with a ...
- 【Codeforces Round】 #431 (Div. 2) 题解
Codeforces Round #431 (Div. 2) A. Odds and Ends time limit per test 1 second memory limit per test ...
- leetcode & lintcode 题解
刷题备忘录,for bug-free 招行面试题--求无序数组最长连续序列的长度,这里连续指的是值连续--间隔为1,并不是数值的位置连续 问题: 给出一个未排序的整数数组,找出最长的连续元素序列的长度 ...
- Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 2) 题解
Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 2) 题目链接:https://codeforces.com/contest/1130 ...
- CF 1130A 1130B 1130C1129A1 1129A2 1129B(Round542A B C D1 D2 E)题解
A : Be Positive 题目地址:https://codeforces.com/problemset/problem/1130/A 题解:让你求是否满足一个d使得数列长为n的a数组的每个数除以 ...
- 【CodeChef】Find a special connected block - CONNECT(斯坦纳树)
[CodeChef]Find a special connected block - CONNECT(斯坦纳树) 题面 Vjudge 题解 还是一样的套路题,把每个数字映射到\([0,K)\)的整数, ...
随机推荐
- jenkins报错The goal you specified requires a project to execute but there is no POM inthis directory
报错截图及详细: 15:30:29[ERROR]The goal you specified requires a project to execute but there is no POM i ...
- ARTS第八周
1.Algorithm:每周至少做一个 leetcode 的算法题2.Review:阅读并点评至少一篇英文技术文章3.Tip:学习至少一个技术技巧4.Share:分享一篇有观点和思考的技术文章 以下是 ...
- excle名字后面直接跟别的出来
名字后面直接跟别的出来 =IF($E6="","",VLOOKUP(E6,通讯录!$B$2:$D$1000,3,0)) $E6:是填写位置的地方 VLOOKUP ...
- 求数组的子数组之和的最大值II
这次在求数组的子数组之和的最大值的条件下又增加了新的约束: 1.要求数组从文件读取. 2.如果输入的数组很大, 并且有很多大的数字, 就会产生比较大的结果 (考虑一下数的溢出), 请保 ...
- 在Springboot + Mybaitis-plus 项目中利用Jackson实现json对java多态的(反)序列化
Jackson允许配置多态类型处理,当JSON面对的转换对象是一个接口.抽象类或者一个基类的时候,可以通过一定配置实现JSON的转换.在实际项目中,Controller层接收入参以及在Dao层将对象以 ...
- 如何在 PyCharm 中设置 Python 代码模板
#!/usr/bin/env python # -*- coding: utf-8 -*- # Created by iFantastic on $DATE if __name__ == '__mai ...
- 分布式ID生成器(CosId)的设计与实现
分布式ID生成器(CosId)设计与实现 CosId 简介 CosId 旨在提供通用.灵活.高性能的分布式 ID 生成器. 目前提供了俩类 ID 生成器: SnowflakeId : 单机 TPS 性 ...
- 【贪心】数列分段Section I luogu-1181
题目描述 对于给定的一个长度为\(N\)的正整数数列\(A_i\),现要将其分成连续的若干段,并且每段和不超过\(M\)(可以等于\(M\)),问最少能将其分成多少段使得满足要求. 分析 简单思考一下 ...
- mysql安装简书
mysql下载地址:https://dev.mysql.com/downloads/mysql/ mysql可视化工具下载地址:https://dev.mysql.com/downloads/work ...
- videojs文档翻译-Player(v6.0.0-RC.2)
Player 当使用任何Video.js设置方法初始化视频时,将创建Player类的实例. 创建实例后,可以通过两种方式在全局访问: 调用videojs('example_video_1');直接通过 ...