P6192 【模板】最小斯坦纳树——最小斯坦纳树

在这里插入图片描述
根据题意,首先使用链式前向星存图。
在这里插入图片描述

接着设 dp[i][s] 表示以 i 为根的一棵树,包含题目中所要求的集合 S 中所有点的最小代价大佬的解析

我做了个算法流程图,如下:
算法流程图
根据上面的算法流程图,可以知道是需要枚举集合状态的,那么这里就可以使用状态压缩。用二进制的方式来表示是否结点被包含在内,0表示未包含,1表示包含。比如要包含7、8、9三个结点,可以使用三位二进制位的S来表示,S=001B(二进制表示)表示包含第一个结点7,S=010B表示包含第二个结点8,S=011B则表示包含第一和第二个结点,也就是7和8。

给出一个例子,大体的算法流程图如下所示:
算法流程的例子

代码如下:

#include <iostream>
#include <queue>
#include <cstring>
#include <climits>
#include <algorithm>
using namespace std;

const int maxn = 110, maxm = 510 * 2;

struct edge {
    
    
	int to, dis, next;
}e[maxm];

int head[maxn], cnt;
int dp[maxn][1025]; //2^10 = 1024
bool vis[maxn];
int n, m, k, u, v, d, p[11];

inline void add_edge(int u, int v, int d) {
    
    
	cnt++; //cnt为每条边的编号
	e[cnt].to = v;
	e[cnt].dis = d;
	e[cnt].next = head[u];
	head[u] = cnt; 
}

struct node {
    
    
	int pos;
	int dis;
	bool operator <(const node &t) const {
    
    
		return dis > t.dis;
	}
}temp;
priority_queue<node> que;

inline void dijkstra(int s) {
    
    
	memset(vis, 0, sizeof(vis));
	
	while (!que.empty()) {
    
    
		temp = que.top();
		que.pop();
		int cur_pos = temp.pos;
		if (vis[cur_pos]) continue;
		vis[cur_pos] = 1;
		for(int i = head[cur_pos]; i; i = e[i].next) {
    
     //i表示某条边的编号
			int y = e[i].to;
			if (dp[y][s] > dp[cur_pos][s] + e[i].dis) {
    
    
				dp[y][s] = dp[cur_pos][s] + e[i].dis;
				temp.pos = y;
				temp.dis = dp[y][s];
				que.push(temp);
			}
		}
	}
}

void init() {
    
    
	for(int i = 0; i < maxn; i++) {
    
    
		for(int j = 0; j < 1025; j++) {
    
    
			dp[i][j] = INT_MAX;
		}
	}
}

int main() {
    
    
	init();
	cin >> n >> m >> k;
	for(int i = 1; i <= m; i++) {
    
    
		cin >> u >> v >> d;
		add_edge(u, v, d);
		add_edge(v, u ,d);
	}
	
	for (int i=1;i<=k;i++) {
    
    
		cin >> p[i];
		dp[p[i]][1<<(i-1)]=0;
	}
	
	for (int s = 1; s < (1<<k); s++) {
    
     //枚举状态(集合s) 
		for (int i = 1; i <= n; i++) {
    
     //枚举结点 
			for (int subs = s&(s-1); subs; subs = s&(subs-1)) {
    
     //枚举集合s的子集(但不包含s) 
				dp[i][s]=min(dp[i][s],dp[i][subs]+dp[i][s^subs]);
			}
			if (dp[i][s] != INT_MAX) {
    
    
				temp.pos = i;
				temp.dis = dp[i][s];
				que.push(temp);
			}
		}
		
		dijkstra(s);
	}
	
	int ans = INT_MAX;
	for(int i = 1; i <= k; i++) ans = min(ans, dp[p[i]][(1<<k)-1]);
	cout << ans;
	return 0;
}




猜你喜欢

转载自blog.csdn.net/qq_45732909/article/details/122162517