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] = min(dp[i][j], dp[i‘][j]+w[i][j])其中i和i‘之间有边相连

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 55;
const int maxm = 1010;
const int INF = 9999999;
int n, m, k;
int d[maxn][maxn];
int dp[1<<16][maxn], dp2[1<<16], a[1<<16];
int inq[1<<16][maxn];
int first[maxn], cnt;
struct node
{
	int v, w, next;
}e[2222];

struct edge
{
	int u, v, w;
	edge(){}
	edge(int u, int v, int w): u(u), v(v), w(w) {}
};
queue <edge> Q;

void spfa()
{
	while(!Q.empty())
	{
		edge x = Q.front(); Q.pop();
		int u = x.u, v = x.v;
		inq[u][v] = 0;
		for(int i = 0; i < n; i++)
		{
			if(d[v][i] != -1)
			{
				if(dp[u|a[i]][i] > dp[u][v] + d[v][i])
				{
					dp[u|a[i]][i] = dp[u][v] + d[v][i];
					if(!inq[u|a[i]][i] && (u|a[i]) == u)
					{
						inq[u|a[i]][i] = 1;
						Q.push(edge(u|a[i], i, dp[u|a[i]][i]));
					}
				}
			}
		}
	}
}
bool ok(int x)
{
    int ans = 0;
    for(int i = 0; x; i++, x >>= 1)
        ans += (x&1)*(i < k ? 1 : -1);
    return ans == 0;
}

void floyd()
{
	for(int l = 0; l < n; l++)
		for(int i = 0; i < n; i++)
			for(int j = 0; j < n; j++)
				if(d[i][l] != -1 && d[l][j] != -1)
					if(d[i][j] == -1 || d[i][j] > d[i][l]+d[l][j])
						d[i][j] = d[i][l]+d[l][j];
}

void steiner()
{
	int all = (1<<(2*k));
	for(int i = 0; i < all; i++)
		for(int j = 0; j < n; j++)
			dp[i][j] = INF;
	memset(a, 0, sizeof(a));
	for(int i = 0; i < k; i++)
		a[i] = (1<<i), dp[(1<<i)][i] = 0;
	for(int i = k; i < 2*k; i++)
		a[n-2*k+i] = (1<<i), dp[(1<<i)][n-2*k+i] = 0;
	for(int s = 1; s < all; s++)
	{
		for(int i = 0; i < n; i++)
		{
			for(int s0 = (s-1)&s; s0; s0 = (s0-1)&s)
			{
				dp[s][i] = min(dp[s][i], dp[s0|a[i]][i]+dp[(s^s0)|a[i]][i]);
			}
			if(dp[s][i] < INF)
			{
				Q.push(edge(s, i, dp[s][i]));
				inq[s][i] = 1;
			}
		}
		spfa();
	}
	for(int i = 0; i < all; i++)
	{
		dp2[i] = INF;
		for(int j = 0; j < n; j++)
			dp2[i] = min(dp2[i], dp[i][j]);
	}
	for(int i = 1; i < all; i++)
	{
		if(ok(i))
		{
			for(int s = (i-1)&i; s; s = (s-1)&i)
			{
				if(ok(i^s))
					dp2[i] = min(dp2[i], dp2[s]+dp2[i^s]);
			}
		}
	}
	if(dp2[all-1] == INF)
		puts("No solution");
	else
		printf("%d\n", dp2[all-1]);
}
int main()
{
	int T;
	scanf("%d", &T);
	while(T--)
	{
		scanf("%d %d %d", &n, &m, &k);
		memset(d, -1, sizeof(d));
		for(int i = 0; i < m; i++)
		{
			int x, y, z;
			scanf("%d %d %d", &x, &y, &z);
			x--, y--;
			if(d[x][y] == -1 || d[x][y] > z)
				d[x][y] = d[y][x] = z;
		}
		floyd();
		steiner();
	}
	return 0;
}
时间: 2024-10-19 04:48:01

HDU 4085 Peach Blossom Spring 斯坦纳树 状态压缩DP+SPFA的相关文章

HDU 4085 Peach Blossom Spring 记忆化搜索枚举子集 斯坦纳树

题目链接:点击打开链接 题意: 第一行输入n个点 m条可修建的无向边 k个人 下面给出修建的边和修建该边的花费. 开始时k个人在1-k的每个点上(一个点各一人) 目标:从m条给定边中修建部分边使得花费和最小 让k个人移动到 [n-k+1, n] 后面的k个点上(每个点放一个人). 思路: 首先就是一道斯坦纳树,还是先求一个dp数组(求解方法:点击打开链接) dp[i][j] 表示以i为根 ,j为8个点中是否在 i 的子树里 时的最小花费. 现在的问题就是如何求答案. 因为一个人到他的目标点这条路

hdu 4085 Peach Blossom Spring

Peach Blossom Spring 题意:有n个城市,m条路,[1,k]的城市有居民, [n-k+1, n]的城市有庇护所, 现在要修路, 使得每一座城市的居民都可以到达一个庇护所, 并且一个庇护所只能容纳一个城市的居民, 现在求所有城市的居民都能到达庇护所的最小花费. 题解:斯坦纳树跑出花费. d[i][state] = cost, i代表的是第i个城市, state代表的是联通的状态, val代表的是花费. 先跑出所有的d[i][state]的花费.然后由于不需要是联通图, 再最后跑出

HDU 5135 Little Zu Chongzhi&#39;s Triangles(状态压缩dp+Vector)

这道题是水题,当时直接贪心就过了. 多阶段决策,其实应该用dp,他人的代码使用Vector进行预处理. #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<vector> using namespace std; int n, a[12]; double dp[1<<12]; double cal(int a, int b, i

BZOJ2595: [Wc2008]游览计划(斯坦纳树,状压DP)

Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 2030  Solved: 986[Submit][Status][Discuss] Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点:否则表示控制该方块至少需要的志愿者数目. 相邻的整数用 (若干个) 空格隔开,行首行末也可能有多余的空格. Outpu

BZOJ4006: [JLOI2015]管道连接(斯坦纳树,状压DP)

Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1171  Solved: 639[Submit][Status][Discuss] Description 小铭铭最近进入了某情报部门,该部门正在被如何建立安全的通道连接困扰. 该部门有 n 个情报站,用 1 到 n 的整数编号.给出 m 对情报站 ui;vi 和费用 wi,表示情 报站 ui 和 vi 之间可以花费 wi 单位资源建立通道. 如果一个情报站经过若干个建立好的通道可以到达另外一个情报

HDU 4081 Peach Blossom Spring (最小生成树+dfs)

题意:给定一个 n 个点和相应的权值,要求你用 n-1 条边连接起来,其中一条边是魔法边,不用任何费用,其他的边是长度,求该魔法边的两端的权值与其他边费用的尽量大. 析:先求出最小生成树,然后再枚举每一条边,求出最大值,任意两点之间的距离可以通过预处理来解决,最小生成树时,要用prime算法,要不然可能会超时. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #i

HDU 6183 Color it cdq分治 + 线段树 + 状态压缩

Color it Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Problem Description Do you like painting? Little D doesn't like painting, especially messy color paintings. Now Little B is painting. To prevent him from

HDU 3247 Resource Archiver (AC自动机 + BFS + 状态压缩DP)

题目链接:Resource Archiver 解析:n个正常的串,m个病毒串,问包含所有正常串(可重叠)且不包含任何病毒串的字符串的最小长度为多少. AC自动机 + bfs + 状态压缩DP 用最短路预处理出状态的转移.可以优化很多 AC代码: #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <queue> using n

HDU 4085 斯坦纳树模板题

Dig The Wells Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 971    Accepted Submission(s): 416 Problem Description You may all know the famous story "Three monks". Recently they find som