【CCF】201903-5 317号子任务--60分

 

【CCF】201903-5 317号子任务--60分_第1张图片

 

采用经过堆优化的Dijkstra算法+优先级队列只能拿到60分,运行超时。

解题思路:

如果对所有顶点使用Dijkstra,复杂度无疑要上升至n*m*log(m)级别。如果我们只对每个发动机节点使用Dijkstra,复杂度可以下降到k*m*log(m)级别,就可以通过子任务中百分之60的数据。

建立一个n级别大小的优先级队列数组,每个优先级队列按照编号存放到发动机据点的最短距离,这样经过k次Dijkstra算法之后,每个优先级队列将从小到大存放到发动机据点的所有距离,按照题意输出即可。

#include 
#define debug puts("-----")
#define pi (acos(-1.0))
#define eps (1e-8)
#define inf (1<<30)
using namespace std;
const int maxn = 10001;
int n, m, k;
int d[maxn], w[maxn];
//用于创建邻接表的节点
struct Node
{
	int w, v;
};
vector G[maxn];
//堆优化使用的重载括号运算符
struct cmp
{
	bool operator() (const int& a, const int& b) {
		return d[a] > d[b];
	}
};

//用于存放各个节点到发动机据点的优先级队列
priority_queue, greater > res[maxn];

//堆优化的Dijkstra算法
//这里要注意重边的情况,不能提前continue,否则会出现错误。
void Dijkstra(int s) {
	fill(d, d+maxn, inf);
	priority_queue, cmp> q;
	d[s] = 0;
	q.push(s);
	while(!q.empty()) {
		int u = q.top();
		q.pop();
		for (int i = 0; i < G[u].size(); ++i)
		{
			int v = G[u][i].v;
			int w = G[u][i].w;
			if(d[u] + w < d[v]) {
				d[v] = d[u] + w;
				q.push(v);
			}
		}
	}
}

int main(int argc, char const *argv[])
{
	scanf("%d%d%d", &n, &m, &k);
    //每个据点是否为发动机据点
	for (int i = 1; i <= n; ++i)
	{
		scanf("%d", &w[i]);
	}
    //建立邻接表
	for (int i = 0; i < m; ++i)
	{
		Node node1, node2;
		int id1, id2, weight;
		scanf("%d%d%d", &id1, &id2, &weight);
		node1.w = weight; node1.v = id1;
		node2.w = weight; node2.v = id2;
		G[id1].push_back(node2);
		G[id2].push_back(node1);
	}
	for (int i = 1; i <= n; ++i)
	{
		if(w[i] == 1)  {
			Dijkstra(i);
            //对发动机据点使用Dijkstra算法之后将最小距离入队
			for (int j = 1; j <= n; ++j)
			{
				if(d[j] != inf)
					res[j].push(d[j]);
			}
		}
	}
    //输出结果
	for(int i = 1; i <= n; i++) {
		int num = k, count = 0;
		while(!res[i].empty() && num-- > 0) {
			count += res[i].top();
			res[i].pop();
		}
		printf("%d\n", count);
	}

	return 0;
}

只能想到这了,若有更好的算法,请在评论区留言!

你可能感兴趣的:(C++,算法,C,Programming)