题目描述
月亮神树的构造非常神奇,它的枝杈交错纵横,树上甚至存在环路,可以视为一个无向带权连通图的结构。月亮神树有一个核心节点,记为 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<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<queue>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<ctime>
#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);
}