【图论】【最短路】【代码实现】岛屿逃生

前言

蒟蒻原创
U63277 岛屿逃生

题目

n n n个岛屿和 m m m条路径,你不知什么原因,被传送到了第 r r r个岛屿,你必须逃离这里,有一个损坏的传送门(但是你可以修好它)在第 c c c个岛屿,所以你的目标是到达第 c c c个岛屿,你有一个魔法值 t t t,由于你的能力有限,所以如果你想修好传送门,你的魔法值必须为正。在第 x i x_i xi个岛屿到第 y i y_i yi个岛屿有一条路和一个数值 z i z_i zi,当你从第 x i x_i xi个岛屿到第 y i y_i yi个岛屿时(或者从第 y i y_i yi个岛屿到第 x i x_i xi个岛屿时),你的魔法值 t t t要乘上 z i z_i zi z i z_i zi有可能是一个负数,所以你的魔法值 t t t也有可能是负数。一条路你可以重复走多次。

你现在要从第 r r r个岛屿到第 c c c个岛屿,因为传送门有损坏,所以当你到达第 c c c个岛屿时,你当前的魔法值 t t t是正数,你才能修好传送门。

现在要你求逃离这里后魔法值最小可以为多少,如无法逃离则输出 − 1 -1 1

输入

1 1 1行,两个数, n n n m m m( 5 5 5<= n n n<= 3000 3000 3000, n n n<= m m m<= 6000 6000 6000),表示有 n n n个岛屿;
2 2 2~ n + 1 n+1 n+1行,每行三个数, x i x_i xi y i y_i yi z i z_i zi( 1 1 1<= x i x_i xi y i y_i yi<= n n n − 10 -10 10<= z i z_i zi<= 10 10 10 z i ≠ 0 z_i ≠0 zi=0),表示第 x i x_i xi个岛屿到第 y i y_i yi个岛屿有一条路,这个路的数值为 z i zi zi
n n n+ 3 3 3行,两个数, r r r c c c,表示第 r r r个岛屿到第 c c c个岛屿。

输出

一个最小的正数 t t t − 1 -1 1

样例输入#1
3 3
1 2 -1
2 3 -2
1 3 4
1 3
样例输入#2
3 3
1 2 -2
2 3 2
1 3-2
1 3
样例输入#3
5 8
2 3 4
1 3 3
2 4 -2
1 4 -5
3 5 -1
2 5 -2
1 5 3
4 5 2
1 2
样例输出#1
4
样例输出#2
-1
样例输出#3
6
样例解释#1

1 − 2 − 3 1-2-3 123

样例解释#2

两种路径结果是 − 4 -4 4 − 2 -2 2,都不是正数,所以输出 − 1 -1 1

样例解释#3

1 − 3 − 5 − 2 1-3-5-2 1352

思路

麻烦的是高精

我们建一个 2 n 2n 2n的图, 1 1 1 n n n是正数区域, n + 1 n+1 n+1 2 n 2n 2n是负数区域
SPFA时如果遇到负数,就跳区域
意思是读入后建边
如果是正数,就建负数区域互通的和正数区域互通的无向边(因为正数 ∗ * 正数 = = =正数;负数 ∗ * 正数 = = =负数)
如果是负数,就建正数区域通往负数区域和负数区域通往正数区域的无向边(因为正数 ∗ * 负数 = = =负数;负数 ∗ * 负数 = = =正数)
SPFA还是正常的SPFA
特别的是要高精加压位
还有建负数的无向边时要取绝对值,因为分了正负数区域

蒟蒻可能讲的不是很清楚,可以在评论里问我,或与我私聊(852671959)

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const ll N=4010,M=25010,W=300,Y=1e10;
struct BNN{
	ll val[W];
}f[N*2];
BNN operator *(BNN &a,ll &b)//重新定义*为高精乘
{
	BNN ans;ll g=0;
	for(ll i=0;i<W;i++)
	{
		ans.val[i]=a.val[i]*b+g;
		g=ans.val[i]/Y;
		ans.val[i]%=Y;
	}
	return ans;
}
bool operator <(BNN &a,BNN &b)//重新定义<
{
	for(ll i=W-1;i>=0;i--)
	{
		if(a.val[i]>b.val[i]) return false;
		else if(a.val[i]<b.val[i]) return true;
	}
	return false;
}
void dy(BNN &a,BNN b)//将b数组赋到a数组
{
    for(ll i=0;i<W;i++)
        a.val[i]=b.val[i];
}
struct node//邻接表
{
    ll to,next,w;
}a[M*2];
ll ls[2*N],tot,n,m,r,c;
bool v[2*N];
queue<int> q;
void addl(ll x,ll y,ll w)
{
    a[++tot].to=y;
    a[tot].next=ls[x];
    ls[x]=tot;
    a[tot].w=w;
}
void SPFA()//SPFA
{
    for(ll i=1;i<=2*n;i++)
      f[i].val[W-1]=999;
    f[r].val[W-1]=0;
    f[r].val[0]=1;
    q.push(r);
    while(!q.empty())
    {
        ll x=q.front();q.pop();
        for(ll i=ls[x];i;i=a[i].next)
        {
            ll y=a[i].to;BNN z=f[x]*a[i].w;
	            if(z<f[y]){
                dy(f[y],z);
                if(!v[y]){
                    v[y]=true;
                    q.push(y);
                }
            }
        }
        v[x]=false;
    }
}
void write(BNN as)
{
	if(as.val[W-1]==999){printf("-1");return;}//判断是否为0
	ll w=W-1;
    while(!as.val[w]) w--;
	printf("%lld",as.val[w]);
    while(w--)//压位
    {
        if(as.val[w]<1e8) putchar('0');
        if(as.val[w]<1e7) putchar('0');
        if(as.val[w]<1e6) putchar('0');
        if(as.val[w]<1e5) putchar('0');
        if(as.val[w]<1e4) putchar('0');
        if(as.val[w]<1e3) putchar('0');
        if(as.val[w]<1e2) putchar('0');
        printf("%lld",as.val[w]);
    }
}
int main()
{
	freopen("date.in","r",stdin);
	freopen("date.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=m;i++){
        ll x,y,z;
        scanf("%lld%lld%lld",&x,&y,&z);
        if(z>0){
            addl(x,y,z);
            addl(y,x,z);
            addl(x+n,y+n,z);
            addl(y+n,x+n,z);//赋边(正)
        }
        else{
        	z=abs(z);//见上(思路)
            addl(x,y+n,z);
            addl(y,x+n,z);
            addl(x+n,y,z);
            addl(y+n,x,z);//赋边(负)
        }
    }
    scanf("%lld%lld",&r,&c);
    SPFA();
    write(f[c]);//高精输出
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
引用\[1\]提供了使用Python的networkx库绘制网络图和计算最短加权路径的示例代码。该代码使用了一个包含顶点和边的列表,并使用add_nodes_from和add_weighted_edges_from方法将它们添加到图中。然后,使用nx.shortest_path_length方法计算了从顶点v1到顶点v11的最短加权路径长度为13。\[1\] 引用\[2\]提供了一个计算最短路径的Python程序示例。该程序使用了numpy和networkx库。首先,定义了一个包含顶点和边的列表,并使用add_nodes_from和add_weighted_edges_from方法将它们添加到图中。然后,使用nx.shortest_path_length方法计算了最短路径长度,并将结果存储在一个字典中。接下来,使用numpy创建了一个6x6的零矩阵,并使用两个嵌套的for循环将最短路径长度填充到矩阵中。最后,使用矩阵乘法计算了运力,并找到了最小运力和对应的位置。\[2\] 引用\[3\]提供了关于Dijkstra算法的一些背景信息。Dijkstra算法是一种寻找最短路径的算法,适用于所有权重大于等于0的情况。它可以用于解决从一个起始点到任意一个点的最短路径问题。\[3\] 综上所述,如果你想在Python中计算图论中的最短路径,可以使用networkx库和Dijkstra算法。你可以根据引用\[1\]和引用\[2\]中的示例代码进行操作。 #### 引用[.reference_title] - *1* *3* [运筹学——图论与最短距离(Python实现)](https://blog.csdn.net/weixin_46039719/article/details/122521276)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [数学建模:图论模型 — 最短路模型示例 (Python 求解)](https://blog.csdn.net/qq_55851911/article/details/124776487)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值