【tyvj1293】小v的红豆(次短路---一条路只能经过一次)

题目:我是超链接

题解:

和那个A*的k短路差异应该在:一条路只能经过一次(那你倒是说清楚啊喂!)

然后一波次短路:

我们要对一个有向赋权图(无向图每条边可以看作两条相反的有向边)的顶点S到T之间求次短路径,首先应求出S的单源最短路径。遍历有向图,标记出可以在最短路径上的边,加入集合K。然后枚举删除集合K中每条边,求从S到T的最短路径,记录每次求出的路径长度值,其最小值就是次短路径的长度。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#define INF 1e9
#define N 1005
#define M 4005
using namespace std;
int tot,nxt[M],point[N],v[M],c[M],dis[N],u[M],pre[N];
bool vis[N];
struct hh{int v,f;};
bool operator <(const hh &a,const hh &b){return a.f>b.f;};
void addline(int x,int y,int z)
{
	++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; u[tot]=x; c[tot]=z;
	++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; u[tot]=y; c[tot]=z;
}
int dij(int s,int t,int id)
{
	memset(dis,0x7f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    priority_queue <hh> q;
    dis[s]=0;
    q.push((hh){s,0});
    while (!q.empty())
    {
    	hh now=q.top(); q.pop();
    	int x=now.v;
		if (vis[x]) continue; 
		vis[x]=1;
		for (int i=point[x];i;i=nxt[i])
    	  if (!vis[v[i]] && dis[v[i]]>dis[x]+c[i])
    	  {
    	  	dis[v[i]]=dis[x]+c[i];
    	  	if (id==1) pre[v[i]]=i;
    	  	q.push((hh){v[i],dis[v[i]]});
		  }
	}
	return dis[t];
}
int main()
{
	int n,m,s,t,i;
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for (i=1;i<=m;i++) 
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		addline(x,y,z);
	}
	int ans1=dij(s,t,1),ans2=INF;
	if (ans1>INF){printf("He lose his love");return 0;} 
	for (i=t;i!=s;i=u[pre[i]])
	{
		int la=c[pre[i]];
		c[pre[i]]=INF;
		ans2=min(ans2,dij(s,t,2));
		c[pre[i]]=la;
	}
	if (ans2==INF){printf("He will be cursed");return 0;} 
	printf("%d",ans2);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值