前言
蒟蒻原创
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 1−2−3
样例解释#2
两种路径结果是 − 4 -4 −4和 − 2 -2 −2,都不是正数,所以输出 − 1 -1 −1
样例解释#3
1 − 3 − 5 − 2 1-3-5-2 1−3−5−2
思路
麻烦的是高精
我们建一个
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;
}