HDU 4085 斯坦纳树
题目大意:
给定无向图,让前k个点都能到达后k个点(保护地)中的一个,而且前k个点每个需要占据后k个中的一个,相互不冲突
找到实现这个条件达到的选择边的最小总权值
这里很容易看出,最后选到的边不保证整个图是联通的
我们只要计算出每一个连通的最小情况,最后跑一遍dfs就能计算出答案了
那么用dp[i][j]表示 i 点为根得到联通状态为 j 的情况需要选到的边的最小总权值
这个用斯坦纳树的思想就可以做到的
对于每一个状态,都用spfa跑一遍得到最优解
dp[i][j] = min(dp[i][j] , dp[k][j]+w[i][k])
而对于每一个点来说就有 dp[i][j] = min(dp[i][j] , dp[i][k]+dp[i][j-k]) (k&j = k)
最后选出所有符合的状态的联通块,dfs找到最优解
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <iostream>
using namespace std;
#define pii pair<int,int>
const int MAX = <<;
const int INF = 0x3f3f3f3f;
int T , n , m , k;
vector<pii> vec[];
int dp[][MAX] , id[];
bool inq[];
queue<int> que; void init()
{
for(int i= ; i<=n ; i++) vec[i].clear();
memset(dp , 0x3f , sizeof(dp));
} void add_edge(int u , int v , int w)
{
vec[u].push_back(make_pair(v , w));
vec[v].push_back(make_pair(u , w));
} void spfa(int cur)
{
while(!que.empty()){
int u = que.front();
// cout<<"inq: "<<u<<endl;
que.pop(); inq[u]=false;
int l = vec[u].size();
for(int i= ; i<l ; i++){
int to = vec[u][i].first;
if(dp[to][cur] > dp[u][cur]+vec[u][i].second){
dp[to][cur] = dp[u][cur]+vec[u][i].second;
if(!inq[to]){
inq[to] = true;
que.push(to);
}
}
}
}
} void get_id()
{
memset(id , , sizeof(id));
for(int i= ; i<=k ; i++){
id[i] = i , dp[i][<<(id[i]-)] = ;
que.push(i);
spfa(<<(id[i]-));
}
for(int i=k+ , j=n; i<=*k ; i++ , j--){
id[j] = i , dp[j][<<(id[j]-)] = ;
que.push(j);
spfa(<<(id[j]-));
}
for(int i=k+ ; i<=n-k ; i++) dp[i][] = ;
} void read_edge()
{
for(int i= ; i<m ; i++) {
int u , v , w;
scanf("%d%d%d" , &u , &v , &w);
add_edge(u , v , w);
}
} void solve()
{
int all = <<(*k);
for(int cur= ; cur<all ; cur++){
for(int i= ; i<=n ; i++){
for(int p=cur&(cur-) ; p ; p=(p-)&cur){
if(dp[i][cur] > dp[i][p]+dp[i][cur-p]){
dp[i][cur] = dp[i][p]+dp[i][cur-p];
if(!inq[i]){
que.push(i);
inq[i]=true;
}
}
}
}
spfa(cur);
}
} //求出得到的子树的最小代价
int tree[MAX] , ok[MAX] , tot , ret; //ok[]记录那些合法的状态,也就是左半部分的1等于右半部分的1 bool is_ok(int x)
{
int cnt = ;
for(int i= ; i<k ; i++) if(x&(<<i)) cnt++;
for(int i=k ; i<*k ; i++) if(x&(<<i)) cnt--;
return cnt == ;
} void get_tree()
{
int all = <<(*k);
tot = ;
for(int cur= ; cur<all ; cur++){
tree[cur] = INF;
for(int i= ; i<=n ; i++) tree[cur] = min(tree[cur] , dp[i][cur]);
if(cur> && is_ok(cur)){
ok[++tot] = cur;
// cout<<tot<<" "<<cur<<" "<<tree[cur]<<endl;
}
}
} void dfs(int p , int cur , int cost , int all)
{
if(cost>ret) return;
if(cur == all){
ret = min(ret , cost);
return;
}
if(p>tot) return;
if(!(cur&ok[p])) dfs(p+ , cur|ok[p] , cost+tree[ok[p]] , all);
dfs(p+ , cur , cost , all);
} int main()
{
// freopen("a.in" , "r" , stdin);
scanf("%d" , &T);
while(T--)
{
scanf("%d%d%d" , &n , &m , &k);
init();
read_edge();
get_id();
solve();
get_tree();
ret = INF;
dfs( , , , (<<(*k))-);
if(ret<INF) printf("%d\n" , ret);
else puts("No solution");
}
return ;
}
HDU 4085 斯坦纳树的更多相关文章
- HDU 4085 斯坦纳树+DP
https://cn.vjudge.net/problem/HDU-4085 给你n,m,k ,分别表示有n个点,m条边,每条边有一个权值,表示修复这条边需要的代价 从前k个点中任取一个使其和后k个点 ...
- hdu 3311 斯坦纳树
思路:虚拟一个0号节点,将每个点建一条到0号节点的边,权值为挖井需要的价值.并要保证0号节点同另外n个寺庙一样被选择即可. 然后就是求斯坦纳树了. #include<map> #inclu ...
- HDU 4085 Peach Blossom Spring 斯坦纳树 状态压缩DP+SPFA
状态压缩dp+spfa解斯坦纳树 枚举子树的形态 dp[i][j] = min(dp[i][j], dp[i][k]+dp[i][l]) 当中k和l是对j的一个划分 依照边进行松弛 dp[i][j] ...
- HDU 3311 Dig The Wells(斯坦纳树)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=3311 [题意] 给定k座庙,n个其他点,m条边,点权代表挖井费用,边权代表连边费用,问使得k座庙里 ...
- HDU - 3311: Dig The Wells (斯坦纳树)
题意:给你n个寺庙,m个村庄,p条路,现在你要在这n+m个位置中选出若干个位置打井,每个位置打井的费用会告诉你,同时p条路也有修建费用,现在每个寺庙都住着一个和尚,问你最小的费用让这n个和尚都能喝上水 ...
- 【BZOJ2595】游览计划(状压DP,斯坦纳树)
题意:见题面(我发现自己真是越来越懒了) 有N*M的矩阵,每个格子有一个值a[i,j] 现要求将其中的K个点(称为关键点)用格子连接起来,取(i,j)的费用就是a[i,j] 求K点全部连通的最小花费以 ...
- hdu4085 Peach Blossom Spring 斯坦纳树,状态dp
(1)集合中元素表示(1<<i), i从0开始 (2)注意dp[i][ss] = min(dp[i][ss], dp[i][rr | s[i]] + dp[i][(ss ^ rr) | s ...
- bzoj 4006 [JLOI2015]管道连接(斯坦纳树+状压DP)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4006 [题意] 给定n点m边的图,连接边(u,v)需要花费w,问满足使k个点中同颜色的 ...
- bzoj 2595 [Wc2008]游览计划(斯坦纳树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2595 [题意] 给定N*M的长方形,选最少权值和的格子使得要求的K个点连通. [科普] ...
随机推荐
- iOS开发 UIPanGestureRecognizer手势抽象类
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@sel ...
- Hbase之插入数据
/** * Created by similarface on 16/8/17. */ import org.apache.hadoop.conf.Configuration; import org. ...
- C++ Primer 第三章 标准库类型vector+迭代器iterator 运算
1.vector: 标准库类型vector表示对象的集合,其中所有对象的类型都相同,集合中的每个对象都有一个与之对应的索引,索引用于访问对象.因为vector“容纳着”其他对象,所以它也常被称作容器( ...
- Android SQlite详解
在项目开发中,我们或多或少都会用到数据库.在Android中,我们一般使用SQLite,因为Android在android.database.sqlite包封装了很多SQLite操作的API.我自己写 ...
- 关于ipxe启动的几个疑问
关于ipxe启动的几个疑问 http://bbs.wuyou.net/forum.php?mod=viewthread&tid=373026&page=1&extra=#pid ...
- Element can be click when out of view
WebDriver can't action the element when out of view Webdriver can't action the element when the elem ...
- 集成代码编辑器ACE的经验
ACE是最流行的在线代码编辑器之一,在CanTK的集成开发环境GameBuilder里也使用了ACE.ACE的功能非常强大,但是由于使用方法不当,大家反映GameBuilder的代码编辑器不好用.最近 ...
- java 集合(Vector)不做重点
Vector: 底层也是维护了一个Object数组,实现与ArrayList是一样的, 但其线程是安全的,效率低.除了比较老的系统,是不会用到的. 笔试题:ArrayList 和 Vector 的区别 ...
- fushioncharts的使用教程
FusionCharts 是使用javascript 实现统计图表的js组件:其官网地址:http://www.fusioncharts.com.其早期版本FusionCharts Free 是基于f ...
- DI 之 3.3 更多DI的知识(陆)
3.3.1 延迟初始化Bean 延迟初始化也叫做惰性初始化,指不提前初始化Bean,而是只有在真正使用时才创建及初始化Bean. 配置方式很简单只需在<bean>标签上指定 " ...