题目

题目大意

给你一个图,让你选择权值和最小的边,使得\(1\)和\(n\),\(2\)和\(n-1\),……,\(K\)和\(n-K+1\)联通。

\(K\leq 4\)


思考历程

一看到这题就觉得特别神仙……

然后去思考网络流……

搞出了一个最小割,后来发现这是错的……

匆匆打了个表,获得了这题的十分之一的分数。


正解

其实这题有水法,许多人是全排列+\(SPFA\),跑了一遍之后将路过的边清\(0\),继续跑。这样贪心显然是错的,反例也有,但是极其水的数据居然给了他们\(100\)分!

正解是DP。

题解中有个叫做\(stenir \ tree\)的东西,感觉似乎很强大。当然我不懂,我只会DP。

现在我们是要求出一个最小生成森林,使得一些点对联通。

考虑一棵树。显然,树的叶子节点一定是要求联通的节点(反过来倒不一定)。

于是我们就试着DP……

设\(f_{S,i}\)表示当前这棵树的根节点为\(i\),并且\(S\)集合中的所有点连在了一起的最小代价

转移的时候就是两棵树的根节点连在一起,也就是\(f_{S',i}+w(i,j)+f_{S-S',j}\to f_{S,i}\)

\(S'\)是\(S\)的子集。(枚举\(S\)和\(S'\)的时间复杂度是\(3^k\)的,\(k\)表示位数,具体实现比较巧妙,见代码)

然后这道题就差不多完了。注意,转移的时候一般是\(S\)从低到高转移,但也会向\(S\)相等的状态转移,这就意味着会有后效性。所以,对于同层的转移,我们特殊地用最短路算法来处理。


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
inline void update(int &a,int b){a>b?a=b:0;}
#define N 10010
#define M 10010
int n,m,K;
struct EDGE{
int to,len;
EDGE *las;
} e[M*2];
int ne;
EDGE *last[N];
inline void link(int u,int v,int len){
e[ne]={v,len,last[u]};
last[u]=e+ne++;
}
int f[256][N],*dis;
struct Node{
int x,dis;
} h[1000001];
int nh;
inline bool cmph(const Node &son,const Node &fa){
return son.dis>fa.dis;
}
int mn[256],ans[256];
inline bool ok(int s){
for (int i=0;i<K;++i)
if ((s>>i&1)^(s>>i+K&1))
return 0;
return 1;
}
int main(){
freopen("in.txt","r",stdin);
scanf("%d%d%d",&n,&m,&K);
for (int i=1;i<=m;++i){
int u,v,len;
scanf("%d%d%d",&u,&v,&len);
link(u,v,len),link(v,u,len);
}
memset(f,63,sizeof f);
for (int i=1;i<=K;++i)
f[1<<i-1][i]=f[1<<K+i-1][n-i+1]=0;
for (int i=K+1;i<=n-K;++i)
f[0][i]=0;
for (int s=1;s<1<<K*2;++s){
for (int i=1;i<=n;++i)
for (int s1=(s-1)&s;s1;s1=(s1-1)&s)
if (f[s1][i]<0x3f3f3f3f)
for (EDGE *ei=last[i];ei;ei=ei->las)
update(f[s][i],f[s1][i]+ei->len+f[s-s1][ei->to]);
dis=f[s];
nh=0;
for (int i=1;i<=n;++i)
h[nh++]={i,dis[i]};
while (nh){
int x=h[0].x,disx=h[0].dis;
pop_heap(h,h+nh--,cmph);
if (disx>dis[x])
continue;
for (EDGE *ei=last[x];ei;ei=ei->las)
if (disx+ei->len<dis[ei->to]){
dis[ei->to]=disx+ei->len;
h[nh++]={ei->to,dis[ei->to]};
push_heap(h,h+nh,cmph);
}
}
mn[s]=INT_MAX;
for (int i=1;i<=n;++i)
update(mn[s],dis[i]);
}
memset(ans,63,sizeof ans);
ans[0]=0;
for (int s=1;s<1<<K*2;++s)
for (int s1=s;s1;s1=(s1-1)&s)
if (ok(s-s1) && ok(s1))
update(ans[s],ans[s-s1]+mn[s1]);
if (ans[(1<<K*2)-1]<0x3f3f3f3f)
printf("%d\n",ans[(1<<K*2)-1]);
else
printf("-1\n");
return 0;
}

总结

不是什么题都能用网络流做的……

DP也能玩出各种花样……

[JZOJ3400] 【GDOI2014模拟】旅行的更多相关文章

  1. GDOI2014模拟 旅行【SPFA】

    旅行(travel) 从前有一位旅者,他想要游遍天下所有的景点.这一天他来到了一个神奇的王国:在这片土地上,有n个城市,从1到n进行编号.王国中有m条道路,第i条道路连接着两个城市ai,bi,由于年代 ...

  2. 【JZOJ6419】模拟旅行&【BZOJ5506】【luoguP5304】旅行者

    description 某国有n座城市,这些城市之间通过m条单向道路相连,已知每条道路的长度. 不过,小X只对其中k座城市感兴趣. 为了更好地规划模拟旅行路线,提升模拟旅行的体验,小X想要知道他感兴趣 ...

  3. 【GDOI2014模拟】JZOJ2020年8月14日提高组 服务器

    [GDOI2014模拟]JZOJ2020年8月14日提高组 服务器 题目 Time and Memory Limits Description 我们需要将一个文件复制到n个服务器上,这些服务器的编号为 ...

  4. 【GDOI2014模拟】JZOJ2020年8月14日T2 网格

    [GDOI2014模拟]JZOJ2020年8月14日T2 网格 题目 Time and Memory Limits Description 某城市的街道呈网格状,左下角坐标为A(0, 0),右上角坐标 ...

  5. GDOI2014模拟pty爬山(mountain)

    pty爬山(mountain) 在Pty学校附近,有一座名之为岳之麓的高山.Pty很喜欢和(哔--)一起爬山.山的平面模型如下:山由一个顶点集:A1,A2-An给定,保证Ai的x单调递增.我们将Ai和 ...

  6. 【GDOI2014模拟】服务器

    前言 直到比赛最后几分钟,才发现60%数据居然是一个水dp,结果没打完. 题目 我们需要将一个文件复制到n个服务器上,这些服务器的编号为S1, S2, -, Sn. 首先,我们可以选择一些服务器,直接 ...

  7. 【GDOI2014模拟】Tree

    题目 Wayne 在玩儿一个很有趣的游戏.在游戏中,Wayne 建造了N 个城市,现在他想在这些城市间修一些公路,当然并不是任意两个城市间都能修,为了道路系统的美观,一共只有M 对城市间能修公路,即有 ...

  8. 【GDOI2014模拟】网格

    题目 某城市的街道呈网格状,左下角坐标为A(0, 0),右上角坐标为B(n, m),其中n >= m.现在从A(0, 0)点出发,只能沿着街道向正右方或者正上方行走,且不能经过图示中直线左上方的 ...

  9. 【GDOI2014模拟】雨天的尾巴

    题目 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连 根拔起,以及田地里 ...

随机推荐

  1. Redis数据结构之字符串-SDS

    C语言中,传统的字符串表示是以空字符结尾的字符数组,Redis的字符串没有直接使用该表示,而是选择构建了一种名为简单动态字符串(simple dynamic string, SDS)的抽象类型. 在R ...

  2. hdu6395 /// 分块矩阵快速幂

    题目大意: F(1)=A, F(2)=B,  F(i)=C*F(i-2)+D*F(i-1)+p/i(向下取整) 给定A B C D p n 求F(n) 构造 矩阵A *   矩阵B        =  ...

  3. Linux编程获取本机IP地址

    使用函数getifaddrs来枚举网卡IP,当中使用到的结构体例如以下所看到的: struct ifaddrs { struct ifaddrs *ifa_next; /* Next item in ...

  4. python--面向对象:类和对象命名空间

    一.一个类可以定义两种属性:静态属性和动态属性 (一)对于不可变数据类型来说,类变量最好用类名操作,也可以用对象操作,但是只能查,不能改,对象改的都只是相当于在自己的命名空间里重新建立了一个 clas ...

  5. 修改css样式+jq中的效果+属性操作+元素操作

    :checked    选框选中的 一.修改css样式: 1.参数只写属性名,则返回属性值 $(this).css( ' color ');   //300px 2.参数是属性名,属性值,逗号分隔,是 ...

  6. 2019-9-2-win10-uwp-布局

    title author date CreateTime categories win10 uwp 布局 lindexi 2019-09-02 12:57:38 +0800 2018-2-13 17: ...

  7. Linux grep return code

    The exit code is 1 because nothing was matched by grep. EXIT STATUS The exit status is 0 if selected ...

  8. drop,delete与truncate的区别

    drop直接删掉表 truncate删除表中数据,再插入时自增长id又从1开始 delete删除表中数据,可以加where字句. (1) DELETE语句执行删除的过程是每次从表中删除一行,并且同时将 ...

  9. PHP rand() 函数

    定义和用法 rand() 函数生成随机整数. 提示:如果您想要一个介于 10 和 100 之间(包括 10 和 100)的随机整数,请使用 rand (10,100). 提示:mt_rand() 函数 ...

  10. centos 服务器编译安装apache+php

    1.检查服务器中是否自带httpd,如果/etc/httpd/httpd.conf,说明系统自带httpd服务,需要卸载或关闭服务,不要让他影响到本次安装的服务启动 可以用 service httpd ...