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个点连通. [科普] ...
随机推荐
- Android自动检测版本及自动升级
步骤: 1.检测当前版本的信息AndroidManifest.xml-->manifest-->android:versionName. 2.从服务器获取版本号(版本号存在于xml文件中) ...
- Maven——eclipse中使用Maven创建Web项目
原文:http://www.cnblogs.com/xdp-gacl/p/4054814.html 一.创建Web项目 1.1 选择建立Maven Project 选择File -> New - ...
- [转]C++中引用(&)的用法和应用实例
from: here 对于习惯使用C进行开发的朋友们,在看到c++中出现的&符号,可能会犯迷糊,因为在C语言中这个符号表示了取地址符,但是在C++中它却有着不同的用途,掌握C++的&符 ...
- JVM调优总结(转)
欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://g ...
- PHP程序员面试技巧之口试题分享
网络上流传很广的一部分php工程师面试题目,有些phper们认为这些很形式,天下面试题目一大把,不能考核一个人的真实水平,其实细细研究起来,无论怎样,能存在就表明其有存在的价值.下面小编整理了12条P ...
- ASP.NET Web API中的依赖注入
什么是依赖注入 依赖,就是一个对象需要的另一个对象,比如说,这是我们通常定义的一个用来处理数据访问的存储,让我们用一个例子来解释,首先,定义一个领域模型如下: namespace Pattern.DI ...
- Objective-C:Foundation框架-常用类-NSArray
NSArray是用来存储对象的有序列表(NSSet是没有顺序的),它是不可变的.NSArray不能存储C语言中的基本数据类型,如int\float\enum\struct等,也不能存储nil.其用法如 ...
- @media用法。
@media版本:CSS2 兼容性:IE5+ 语法: @media sMedia { sRules } 说明: sMedia : 指定设备名称.请参阅附录:设备类型 sR ...
- (巨坑)改了tpl文件之后,前端效果没反应
通常前端修改很小的部分代码,并不会立即显示出效果.比如,原来是 ,修改后是 虽然只是加多了一个函数,但是作用很大,这种情况下,可能是由于浏览器缓存的原因,修改后的代码没有被重新加载.这个时候,只需要在 ...
- JBoss JMX登录需要用户名密码的解决办法
/opt/jboss/eap5.1.2/jboss-as/server/default/conf/props/jmx-console-users.properties 取消#admin=admin的注 ...