计蒜客 热爱工作的蒜蒜 spfa+dfs

众所周知,蒜蒜是一名热爱工作的好员工,他觉得时间就是金钱,做事情总是争分夺秒。

这天晚上,蒜蒜一个人去吃晚饭。不巧的是,吃完饭以后就开始下雨了,蒜蒜并没有带雨伞出来。但是蒜蒜热爱工作,工作使他快乐,他要尽快赶回去写代码。

蒜蒜的公司在中关村,中关村这边地形复杂,有很多天桥、地下通道和马路交错在一起。其中,地下通道是可以避雨的,天桥和马路都没办法避。可以把中关村抽象成为 nnn 个点的地图(顶点编号为 111nnn),其中有 m1m_1m1 条地下通道,有 m2m_2m2 条马路或者天桥,其中地下通道的长度为 111。蒜蒜吃饭的地方在 111 点,公司在 nnn 点。当然,蒜蒜虽然爱工作心切,但是他更不想淋很多雨,同时也不想浪费很多时间。于是他折中了一下——在保证他回到公司所走的路程总和小于等于 LLL 的情况下,他希望淋雨的路程和尽量的少。

请你赶紧帮热爱工作的蒜蒜规划一条路径吧,不要再让他浪费时间。

输入格式

第一行输入测试组数 T(1≤T≤20)T(1 \le T \le 20)T(1T20)

接下来 TTT 组数据。

每一组数据的第一行输入四个整数 n(2≤n≤100)n(2 \le n \le 100)n(2n100)m1(0≤m1≤50)m_1(0 \le m_1 \le 50)m1(0m150)m2(0≤m2≤5000)m_2(0 \le m_2 \le 5000)m2(0m25000)L(1≤L≤108)L(1 \le L \le 10^8)L(1L108)

接下里 m1m_1m1 行,每行输入两个整数 a,b(1≤a,b≤n)a, b(1 \le a, b \le n)a,b(1a,bn),表示 aaabbb 之间有一条地下通道。

接下里 m2m_2m2 行,每行输入三个整数 u,v(1≤u,v≤n),c(1≤c≤106)u, v(1 \le u, v \le n), c(1 \le c \le 10^6)u,v(1u,vn),c(1c106),表示 uuuvvv 之间有一条长度为 ccc 的马路或者天桥。

所有路径都是双向的

输出格式

对于每组数据,如果有满足要求的路径,输出一个整数,表示淋雨的路程长度,否则输出 −1-11

样例输入
3
4 2 2 6
1 2
2 3
1 4 5
3 4 4
4 2 2 5
1 2
2 3
1 4 5
3 4 4
4 2 2 4
1 2
2 3
1 4 5
3 4 4
样例输出
4
5
-1
题目来源

景驰无人驾驶 1024 编程邀请赛

 此题wa和tleN次,参考大牛博客

解: 先求出从n到每一个点的最短距离,再对1点进行dfs;

dfs时:①如果从1点当前点的最小淋雨量加上从这点到相邻的下一个点的淋雨量小于从1点下一个点的淋雨量,则更新下一个点的最小淋雨量;否则return

            ②如果从1点到当前点的距离加上与相邻的下一个点的距离,再加上下一个点到n点的最短距离小于限制距离,则继续dfs;否则停止这一条路径的dfs;

#include <iostream>  
#include <algorithm>   
#include <string.h> 
#include <queue> 
using namespace std;  
const int inf=0x3f3f3f3f;;
const int maxx=1e3+100;;
const int maxn=2e6+10;
typedef long long ll;
int m1,m2,n,q,L;  
int dis[maxx],dis2[maxx];
int sto[maxx];
int pre[maxx];
int head[2*maxn];
bool vis[maxx],vis2[maxx],vis3[maxx]; 
int nu[maxx],flag;
struct  point{    
    int to;  
    int next; 
	int val;
	int val2;
};  
point pt[2*maxn]; 
void add(int u,int v,int val)
{
	      pt[q].next=head[u];  
          pt[q].to=v;
		  pt[q].val=val;
		  pt[q].val2=val;
		  if (flag)
		  pt[q].val2=0;
		  head[u]=q++;
} 
void spfa(int st)  
{  
    queue<int>q;
	int w,v;
    memset(dis,inf,sizeof(dis));
    memset(vis,false,sizeof(vis));
    q.push(st);
    dis[st]=0;
    vis[st]=true;
    while (!q.empty())
    {
    	v=q.front();
    	q.pop();
    	vis[v]=false;
    	for (int i=head[v];i!=-1;i=pt[i].next)
    	{
    		w=pt[i].val;
    		if (w+dis[v]<dis[pt[i].to])
    		{
    			 dis[pt[i].to]=w+dis[v];
    			  if (!vis[pt[i].to])
    			 {
    				vis[pt[i].to]=true;
    				q.push(pt[i].to);
				 }
			}
		}   
    }

}  
void dfs(int st,int number,int number2)
{
    if (number<nu[st])
	nu[st]=number;
	else
	return;
	if (st==n)
	return;
	for (int i=head[st];i!=-1;i=pt[i].next)
	{
		if (number2+dis[pt[i].to]+pt[i].val<=L&&nu[st]+pt[i].val2<nu[pt[i].to])
		{
			dfs(pt[i].to,nu[st]+pt[i].val2,number2+pt[i].val);
		}
	}
}
int main()  
{  
    int t,t1,va,u,v,val;
    cin>>t;
    while (t--)
	{
		memset(nu,inf,sizeof(nu));
		scanf("%d%d%d%d",&n,&m1,&m2,&L);
        q=1; 
        memset(head,-1,sizeof(head)); 
        flag=1;
        for (int i=0;i<m1;i++)
        {
        	scanf("%d%d",&u,&v);
        	add(u,v,1);
        	add(v,u,1);
		}
		flag=0;
		for (int i=0;i<m2;i++)
		{
			scanf("%d%d%d",&u,&v,&val);
			add(u,v,val);
			add(v,u,val);
		}
		spfa(n);
		if (dis[1]>L)
        printf("-1\n");
        else
        {
         dfs(1,0,0);
         printf("%d\n",nu[n]);
        }
    }
    return 0;  
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值