[NOIP模拟测试]:那一天她里我而去(堆优化Dijkstra)

时间:2022-11-04 20:42:42

题目传送门(内部题3)


输入格式

每个测试点有多组测试数据。
第一行有一个正整数T表示数据组数。
接下来对于每组数据,第一行有两个正整数n,m分别代表图的点数和边数。
接下来有m行,每行三个整数u,v,d表示u,v之间存在一条长度为d的路径。
保证不存在重边,自环。


输出格式

对于每组测试数据,输出题目中所求的最小环的长度。
无解输出-1。


样例

样例输入

2
3 3
1 2 1
2 3 1
3 1 1
4 5
1 2 2
2 3 2
3 4 2
1 4 2
1 3 5

样例输出

3
8


数据范围与提示

$T \leqslant 10$

$d \leqslant {10}^3$

对于30%的数据:

$n \leqslant {10}^3$

$m \leqslant 4 \times {10}^3$

对于另外30%的数据:

$n \leqslant {10}^4$

$m=n$

对于100%的数据:

$n \leqslant {10}^4$

$m \leqslant 4 \times {10}^4$


题解

这道题要求我们找一个包含节点1的最小环,显然直接dfs求会超时,那么我们试图转化问题。

将问题转化成:在与节点1直接项链的节点中找一个点,砍掉它与节点一的连边,然后从这个点沿其他路径跑到节点1,再加上砍掉的这个边的权值,在所有的这些情况中找最小的。

问题就轻松解决了,依次枚举每一个与节点1相连的点即可。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec
{
	int nxt;
	int to;
	int w;
}e[100000];
int n,m;
int head[40001],cnt=1;
int dis[40001];
bool vis[40001];
int ans;
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q;
void pre_work()
{
	cnt=1;
	ans=20020923;
	memset(head,0,sizeof(head));
}
void add(int x,int y,int w)
{
	e[++cnt].nxt=head[x];
	e[cnt].to=y;
	e[cnt].w=w;
	head[x]=cnt;
}
void Dij(int x)
{
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    q.push(make_pair(0,x));
    dis[x]=0;
    while(!q.empty())
    {
        int flag=q.top().second;
        q.pop();
        if(vis[flag])continue;
        vis[flag]=1;
        for(int i=head[flag];i;i=e[i].nxt)
            if(dis[e[i].to]>dis[flag]+e[i].w)
            {
                dis[e[i].to]=dis[flag]+e[i].w;
                q.push(make_pair(dis[e[i].to],e[i].to));
            }
    }
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		pre_work();
		for(int i=1;i<=m;i++)
		{
			int u,v,d;
			scanf("%d%d%d",&u,&v,&d);
			add(u,v,d);
			add(v,u,d);
		}
		for(int i=head[1];i;i=e[i].nxt)
		{
			int flag=e[i].w;
			e[i].w=e[i^1].w=20020923;//把这条边赋成极大值就相当于是删掉了这条边
			Dij(e[i].to);
			ans=min(ans,dis[1]+flag);
			e[i].w=e[i^1].w=flag;
		}
		if(ans==20020923)puts("-1");
		else printf("%d\n",ans);
	}
	return 0;
}

rp++