[图论最短路]D1T2

题目描述

月亮神树的构造非常神奇,它的枝杈交错纵横,树上甚至存在环路,可以视为一个无向带权连通图的结构。月亮神树有一个核心节点,记为 s 。要想消灭月亮神树,必须找到月亮神树的严格最不科学生成树,这是它的弱点,这样就能将其一举摧毁。
定义:一个图 G 的不科学生成树是 G 的一棵子树,在这棵子树上,从核心节点 s 到任意一个节点 u 的最短路径长度,和在原图上是等长的。其中节点 s 是月亮神树的核心节点。
定义:一个图 G 的最不科学生成树是 G 的所有不科学生成树中,边权和最小的一棵树。
定义:一个图 G 的严格最不科学生成树是 G 的所有最不科学生成树中,有序边序列的字典序最小的一棵树。
定义:一个图 G 的有序边序列是指,将图上所有边按编号从小到大排序后得到的编号序列。当然,子图子树也适用。
现在给定月亮神树,即给定一个 n 个点 m 条边的无向带权连通图,点的编号从1到n,边的编号从1到m,给定核心节点的编号 s ,求其严格最不科学生成树。

输入格式

第一行三个正整数 n,m,s 。
接下来 m 行,第 i 行三个正整数 u,v,w ,表示编号为 i 的边。
输入保证图是连通的,保证图上不含重边和自环。。

输出格式

第一行两个正整数 cnt 和 sum ,用空格隔开,其中 cnt 表示严格最不科学生成树的边的个数, sum 表示严格最不科学生成树的边权和。
接下来一行 cnt 个正整数,用空格隔开,为树上所有边的编号,按编号从小到大输出。

【样例1】
moontree.in
3 3 3
1 2 1
2 3 1
1 3 2
moontree.out
2 2
1 2
【样例2】
moontree.in
4 4 4
2 3 1
1 2 1
3 4 1
4 1 2
moontree.out
3 4
1 3 4
【数据规模与约定】
对于25%的数据, 1≤n,m≤10 。
另有25%的数据, 1≤n,m≤100 。
对于100%的数据, 1≤n,m≤3*105 ,1≤wi≤109

题解

考试中最水的一道,然而我就想骗分,想得贼复杂。
题目中写到生成树中核心结点到其他点是对应原图中的最短路距离,肯定跟最短路径有些关系。每个点肯定是通过一些最短路上的边加进生成树当中的。并且只会选择一条(不算核心结点)
首先要生成树边权和最小,则我们取一些权值较小的边替换权值较大的边
而后要选的边从小到大排的字典序最小,在权值相同的情况下取编号小的即可。
整个过程通过dij更新时选择即可。
对,就这。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fi first
#define se second
#define N 300005
using namespace std;
struct node{
	int v,ind;
	long long w;
	node(){};
	node (int V,long long W,int I){
		v = V,w = W,ind = I;
	}
	bool operator < (const node &rhs)const {
		return w > rhs.w;
	}
};
int n,m,s;
long long sum,dis[N];
bool vis[N];
vector<node>G[N];
pair<int,int>ans[N];
bool cmp(pair<int,int> a,pair<int,int> b){
	return a.fi < b.fi;
}
void dij(){
	for (int i = 1;i <= n;i ++)
		dis[i] = (1ll << 60);
	priority_queue<node>Q;
	Q.push(node(s,0,0));
	dis[s] = 0;
	while (!Q.empty()){
		int u = Q.top().v;
		Q.pop();
		if (vis[u])
			continue;
		vis[u] = 1;
		for (int i = 0;i < G[u].size();i ++){
			int v = G[u][i].v,ind = G[u][i].ind;
			long long w = G[u][i].w;
			if (dis[v] > dis[u] + w){
				dis[v] = dis[u] + w;
				ans[v] = make_pair(ind,w);
				Q.push(node(v,dis[v],0));
			}
			if (dis[v] == dis[u] + w){
				if (w < ans[v].se)
					ans[v] = make_pair(ind,w);
				if (w == ans[v].se && ans[v].fi > ind)
					ans[v] = make_pair(ind,w);
			}
		}
	}
}
int main(){
	scanf ("%d%d%d",&n,&m,&s);
	for (int i = 1;i <= m;i ++){
		int u,v,w;
		scanf ("%d%d%d",&u,&v,&w);
		G[u].push_back(node(v,w,i));
		G[v].push_back(node(u,w,i));
	}
	dij();
	sort (ans + 1,ans + 1 + n,cmp);
	for (int i = 2;i <= n;i ++)
		sum += ans[i].se;
	printf("%d %lld\n",n - 1,sum);
	for (int i = 2;i < n;i ++)
		printf("%d ",ans[i].fi);
	printf("%d\n",ans[n].fi);
}

你可能感兴趣的:(图论,最短路,树,dijkstra,最短路,图论)