3669: [Noi2014]魔法森林

题目链接

题解:

如果是一个值得话,那就是超水的spfa,两个值的话,我们可以对spfa稍稍改变一下。

对于每个a我们排个序,那么对于每个其中一个值最大为a,直接求另外那个值最大最小就好了,

注意dis不要每次都清inf,会wa的,为什么?这明显显而易见的嘛,

代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<queue>
#define inf 1e8
using namespace std;
const int N=51000;
const int M=101000;
int n,m;
struct node{
	int x,y,a,b,next;
	bool tf;
}sa[M*2];int len=1,first[N];
struct trpe{
	int id,a;
}ss[M*2];
void ins(int x,int y,int a,int b)
{
	len++;
	sa[len].x=x;
	sa[len].y=y;
	sa[len].a=a;
	sa[len].b=b;
	sa[len].tf=0;
	sa[len].next=first[x];
	first[x]=len;
}
bool cmp(trpe a,trpe b)
{
	return a.a<b.a;
}
int dis[N];
bool tf[N];
queue<int>q;
void spfa()
{
	while(!q.empty())
	{
		int x=q.front();q.pop();tf[x]=0;
		for(int i=first[x];i!=-1;i=sa[i].next)
		{
			int y=sa[i].y;//printf("%d %d %d\n",x,y,i);
			if(sa[i].tf&&dis[y]>max(dis[x],sa[i].b))
			{
				
				dis[y]=max(dis[x],sa[i].b);
				if(!tf[y])
				{
					q.push(y);
					tf[y]=1;
				}
			}
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	memset(first,-1,sizeof(first));
	int x,y,a,b;
	int tot=0;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d%d",&x,&y,&a,&b);
		ins(x,y,a,b);ins(y,x,a,b);
		ss[++tot].id=len-1;ss[tot].a=a;
	}
	sort(ss+1,ss+1+tot,cmp);
	for(int i=1;i<=n;i++) dis[i]=inf;
	bool po=false;dis[1]=0;
	int ans=inf;
	for(int i=1;i<=m;i++)
	{
		int yu=ss[i].id;
		//printf("!%d %d %d\n",yu,yu+1,i);
		sa[yu].tf=1;sa[yu+1].tf=1;
		if(po==true||sa[yu].x==1||sa[yu].y==1)
		{//printf("!!!%d %d %d %d %d\n",sa[yu].x,sa[yu].y,po,i,ss[i].a);
			q.push(sa[yu].x);q.push(sa[yu].y);
			memset(tf,0,sizeof(tf));
			tf[sa[yu].x]=1;tf[sa[yu].y]=1;//printf("%d %d\n",ss[i].a,dis[n]);
			po=true;spfa();ans=min(ans,ss[i].a+dis[n]);
		}
		
}
if(ans==inf) printf("-1");
else
	printf("%d",ans);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值