BZOJ 2407 探险

216 篇文章 0 订阅
48 篇文章 0 订阅

Description

探险家小T好高兴!X国要举办一次溶洞探险比赛,获奖者将得到丰厚奖品哦!小T虽然对奖品不感兴趣,但是这个大振名声的机会当然不能错过!
比赛即将开始,工作人员说明了这次比赛的规则:每个溶洞和其他某些溶洞有暗道相连。两个溶洞之间可能有多条道路,也有可能没有,但没有一条暗道直接从自己连到自己。参赛者需要统一从一个大溶洞出发,并再次回到这个大溶洞。
如果就这么点限制,那么问题就太简单了,可是举办方又提出了一个条件: 不能经过同一条暗道两次。这个条件让大家犯难了。这该怎么办呢?
到了大溶洞口后,小T愉悦地发现这个地方他曾经来过,他还记得有哪些暗道,以及通过每条暗道的时间。小T现在向你求助,你能帮他算出至少要多少时间才能回到大溶洞吗?

Input

第一行两个数n,m表示溶洞的数量以及暗道的数量。

接下来m行,每行4个数 s、t、w、v,表示一个暗道连接的两个溶洞 s、t,这条暗道正着走( s à t)的所需要的时间 w,倒着走( t à s)所需要的时间 v。由于溶洞的相对位置不同, wv可能不同。

Output

输出一行一个数t,表示最少所需要的时间。

Sample Input

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

Sample Output

8

HINT

N<=10000,M<=200000,1<=W,V<=10000

Source

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

dijkstra+思路~

单独处理从1出发后,就可以用最短路来做了。

每个点记录从1到它的最短两条路以及它走的路径是从与1相连的哪条边来的,然后dijkstra即可。

bool operator里面是>啊啊啊啊!


#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;

int n,m,x,y,s,t,fi[10001],w[400001],ne[400001],v[400001],cnt,d1[10001],d2[10001];
int f1[10001],f2[10001],len[10001];

struct node{
	int w,f,dis;
};

bool operator < (node u,node v)
{
	return u.dis>v.dis;
}

int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f; 
}

void add(int u,int vv,int val1,int val2)
{
	w[++cnt]=vv;ne[cnt]=fi[u];fi[u]=cnt;v[cnt]=val1;
	w[++cnt]=u;ne[cnt]=fi[vv];fi[vv]=cnt;v[cnt]=val2;
}

int cal()
{
	priority_queue<node> q;
	memset(d1,0x3f,sizeof(d1));
	memset(d2,0x3f,sizeof(d2));
	int k,f,dis;
	for(int i=fi[1];i;i=ne[i])
	{
		f=i>>1;
		if(d1[w[i]]>v[i])
		{
			if(f1[w[i]]!=f) f2[w[i]]=f1[w[i]],d2[w[i]]=d1[w[i]];
			f1[w[i]]=f;d1[w[i]]=v[i];
		}
		else if(f!=f1[w[i]] && d2[w[i]]>v[i]) f2[w[i]]=f,d2[w[i]]=v[i];
		else continue;
		q.push((node){w[i],f,v[i]});
	}
	while(!q.empty())
	{
		f=q.top().f;k=q.top().w;dis=q.top().dis;q.pop();
		if(!(f==f1[k] && d1[k]==dis) && !(f==f2[k] && d2[k]==dis)) continue;
		for(int i=fi[k];i;i=ne[i])
		  if((i>>1)!=f)
		  {
		  	if(d1[w[i]]>v[i]+dis)
			{
				if(f1[w[i]]!=f) f2[w[i]]=f1[w[i]],d2[w[i]]=d1[w[i]];
				f1[w[i]]=f;d1[w[i]]=v[i]+dis;
			}
			else if(f!=f1[w[i]] && d2[w[i]]>v[i]+dis) f2[w[i]]=f,d2[w[i]]=v[i]+dis;
			else continue;
			q.push((node){w[i],f,v[i]+dis});
		  }
	}
	return d1[1];
}

int main()
{
	n=read();m=read();cnt=1;
	for(int i=1;i<=m;i++) x=read(),y=read(),s=read(),t=read(),add(x,y,s,t);
	printf("%d\n",cal());
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值