2017.11.6与章丘四中互测章丘试题

来源:互联网 发布:网络水军怎么看 编辑:程序博客网 时间:2024/04/28 20:43

首先感谢章丘四中的同学精心准备了这套题并在考试结束后进行了细致讲解。
不过由于你们的题目背景太长了就不放在这里了。

Problem 1 :谜团

题目描述

谜团,是夜魇军团一名强大的战士。他来自远古,是一种不可思议的重力生命体,是来自原始黑暗的扭曲声音,在宇宙中的第一丝光线诞生前就存在的深渊化身。他能动用深渊之力将生物的身体污染,使之转化为自身的碎片“虚灵”。“虚灵”为谜团所控,拥有一定的战斗力。更为恐怖的是,新产生的“虚灵”的第一次攻击将吸收被攻击者内心的黑暗,从而分裂成若干个“虚灵”,之后的攻击将无法产生“虚灵”,新产生的“虚灵”第一次攻击仍可产生“虚灵”。作为天辉军团智囊的你,需要知道某一时刻谜团最多可以产生多少“虚灵”,从而据此来进行决策。
具体的,谜团在第一秒会转化一个单位,使之变成一个“虚灵”,由于能量消耗过大,谜团在之后的时间内将不再转化单位,使之变成“虚灵”。新产生的“虚灵”会在下一秒攻击一次,从而分裂出 m 个“虚灵”,原有的“虚灵”仍然存在,并且将不再产生虚灵。但新产生的“虚灵”可在下一秒攻击一次并分裂,之后也将不再产生“虚灵”(具体见样例解释)。给定时间 t 和分裂数 m,请你告诉天辉军团的战士们,在 t 秒后,谜团拥有多少个“虚灵”。
答案可能很大,要求你模一个数 k(不保证 k 是质数)。

输入格式
第一行:三个整数 m,t,k,意义见题目描述

输出格式
第一行:t 秒后谜团拥有的能量体个数

样例输入 1
3 3 1000

样例输出 1
13

样例输入 2
3 5 1000

样例输出 2
121

样例 1 解释
m = 3, t = 5 时:
第一秒:谜团制造 1 个“虚灵”
第二秒:1 个“虚灵”分裂出 3 个“虚灵”,此时共有 4 个“虚灵”
第三秒:第 1 秒制造的 1 个“虚灵”将不能分裂,第 2 秒制造的 3 个“虚灵”,每个“虚灵”分裂成 3 个“虚灵”,新分裂出的“虚灵”有 9 个,此时共有 13个“虚灵”。
最终,总共有 13 个“虚灵”
数据规模与约定
保证 k,m,t 及答案在 int 范围内

这里写图片描述

思路——主要是我的思路
仔细观察冷静分析后会发现,答案为一首项为1,公比为m的等比数列前t项和…
好吧其实我一开始没看出来….

我的思路是这样,设f[i]表示时间为i时的虚灵数(答案),对于每一个时间的虚灵数,都是由前一时间可以分裂的虚灵分裂出新虚灵(*m),再加上前一时间的虚灵数得到的。而前一时间可以分裂的虚灵数为——前一时间相对于更前一时间新增的虚灵数。
那么我们就得到了:f[i] = m * (f[i-1] - f[i-2])+ f[i],化简一下得:f[i] = (m+1)* f[i-1] - m * f[i-2]
处理出前两项:f[1]=1,f[2]=m+1递推即可。
但显然这样只能过1-8个点。后面的数据空间可以滚动但时间无法承受,此题时限0.5秒。

考虑等比数列求和的思路。
由等比数列求和公式我们得到:ans = (1 - m^t)/(1 - m)
快速幂求解m^t,由于存在除法取模我们还要求一下1 - m的逆元!
费马小定理吗?
不好意思模数k为质数的情况只有9-12个点…..
费马小定理求逆元只适用于模数为质数的情况,于是我们使用扩展欧几里得求逆元,可适用于k为质数或不为质数的情况。
还要注意…求负数(1 - m)的逆元我也不知道会出什么结果,所以我们把上下同乘-1转换为正数求解。
即:ans = (m^t - 1)/(m - 1)

(m - 1)x ≡ 1(mod k)-> (m - 1)x - ky =1,求解x即为(1 - m)在mod k意义下的逆元。
那样9 - 16个点就可以过了?

好吧并没有…这里我要吐槽一下….
首先剩下的点过不了的原因是m与k不互质…费马小定理,扩欧,欧拉定理求逆元都需要互质的条件——但这个互质条件是针对m-1和k的为什么数据范围给的是m和k的关系啊!
这就导致第13个点过不了但是第20个点可以过…..

官方正解:等比数列求和有一变形如下:

Link

设n和m都等于t/2,则有:

Link

递归计算中间过程取模即可。
注意因为我们的除法是下取整的,递归过程中应分奇数偶数分别计算,对于t为偶数的情况,我们用t/2-1的对应值计算,再加上一个q(公差)^t即可。

其他的满分做法:
要不要试着将递推和等比数列的思路结合呢?
我们发现,f[i]为一首项为1,公比为m的等比数列前t项和,那么f[i]就是由f[i-1]加上等比数列的第i项得到的,由等比数列通项公式得:
f[i] = f[i-1] + m^i-1
相比于前面的递推式,我们做到了——将减法转化为了加法。
有什么意义呢?
可以进行矩阵快速幂优化啦~
对于单纯的线性递推问题,如果出现取模过程中出现负数,我们可以通过不断加模数使答案变为正数,但事实上这样的操作在矩阵快速幂中是不太容易实现的。将减法换为加法就可以保证矩阵快速幂的正确性。

代码——80%版本
考试时生怕过不了就写了16层循环展开….卡常算法不要介意…

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define RI register intusing namespace std;typedef long long ll;//unsigned ll不可存储负数..求逆元过程中会出现错误 ll m,k,t,x,y;ll f[7000010],ans;ll por(ll a,ll b){    if(!b)    return 1;    ll tmp=por(a,b>>1);    tmp=tmp*tmp%k;    if(b&1)    tmp=tmp*a%k;    return tmp%k;}bool isprime(ll x){    if(x<=1)    return 0;    for(ll i=2;i*i<=x;i++)    {        if(x%i==0)        return 0;    }    return 1;}ll gcd(ll a,ll b){    return b==0?a:gcd(b,a%b);}ll exgcd(ll a,ll b,ll &x,ll &y){    if(b==0)    {        x=1;        y=0;        return a;    }    ll d=exgcd(b,a%b,x,y);    ll tmp=x;    x=y;    y=tmp-a/b*y;    return d;}int main(){    scanf("%lld%lld%lld",&m,&t,&k);    if(t<=5000000)    {        f[1]=1;        f[2]=m+1;        for(RI i=3;i<=t;i+=16)        {            f[i]=(((((m+1)%k)*(f[i-1]%k))%k)-(((m%k)*(f[i-2]%k))%k)+2*k)%k;            f[i+1]=(((((m+1)%k)*(f[i]%k))%k)-(((m%k)*(f[i-1]%k))%k)+2*k)%k;            f[i+2]=(((((m+1)%k)*(f[i+1]%k))%k)-(((m%k)*(f[i]%k))%k)+2*k)%k;            f[i+3]=(((((m+1)%k)*(f[i+2]%k))%k)-(((m%k)*(f[i+1]%k))%k)+2*k)%k;            f[i+4]=(((((m+1)%k)*(f[i+3]%k))%k)-(((m%k)*(f[i+2]%k))%k)+2*k)%k;            f[i+5]=(((((m+1)%k)*(f[i+4]%k))%k)-(((m%k)*(f[i+3]%k))%k)+2*k)%k;            f[i+6]=(((((m+1)%k)*(f[i+5]%k))%k)-(((m%k)*(f[i+4]%k))%k)+2*k)%k;            f[i+7]=(((((m+1)%k)*(f[i+6]%k))%k)-(((m%k)*(f[i+5]%k))%k)+2*k)%k;            f[i+8]=(((((m+1)%k)*(f[i+7]%k))%k)-(((m%k)*(f[i+6]%k))%k)+2*k)%k;            f[i+9]=(((((m+1)%k)*(f[i+8]%k))%k)-(((m%k)*(f[i+7]%k))%k)+2*k)%k;            f[i+10]=(((((m+1)%k)*(f[i+9]%k))%k)-(((m%k)*(f[i+8]%k))%k)+2*k)%k;            f[i+11]=(((((m+1)%k)*(f[i+10]%k))%k)-(((m%k)*(f[i+9]%k))%k)+2*k)%k;            f[i+12]=(((((m+1)%k)*(f[i+11]%k))%k)-(((m%k)*(f[i+10]%k))%k)+2*k)%k;            f[i+13]=(((((m+1)%k)*(f[i+12]%k))%k)-(((m%k)*(f[i+11]%k))%k)+2*k)%k;            f[i+14]=(((((m+1)%k)*(f[i+13]%k))%k)-(((m%k)*(f[i+12]%k))%k)+2*k)%k;            f[i+15]=(((((m+1)%k)*(f[i+14]%k))%k)-(((m%k)*(f[i+13]%k))%k)+2*k)%k;        }        printf("%lld",f[t]);    }    else//等比数列求和得到的新数列,首项为1,公差为3     {        if(gcd(m-1,k))//m-1,k互质,exgcd可处理k为质数或不为质数的情况         {            exgcd(m-1,k,x,y);//m,k不互质那么m-1和k呢?             ans=((por(m,t)-1)%k*x%k)%k;         }        while(ans<0)        ans+=k;//exgcd求逆元答案可能为负数         printf("%llu",ans);    }    return 0;}


代码——官方正解

#include <bits/stdc++.h>inline void read(long long &x){    x=0;    char ch=getchar(),c=ch;    while(ch<'0'||ch>'9')    c=ch,ch=getchar();    while(ch<='9'&&ch>='0')    x=x*10+ch-'0',ch=getchar();    if(x=='-')    x=-x; }long long t, m, k;long long pow(long long a,long long b){    long long r=1,base=a;    for(;b;b>>=1)    {        if(b&1)         r*=base,r%=k;        base*=base,base%=k;    }    return r;}long long sum(long long p,long long c){    if(c==0)     return 1;    if(!(c&1))    return (sum(p,c/2-1)*(1+pow(p,c/2))%k+pow(p,c))%k;    else return sum(p,c/2)*(1+pow(p,c/2+1))%k;}int main(){    read(m),read(t),read(k);    printf("%lld", sum(m,t-1));    return 0;} 


失误
考场上把递推的初始状态f[2]用样例的数据设为了4….而不是m+1
十分显然的等比数列没看出来….
一定要注意仔细观察细致分析….还有不要浪费时间在无用工作上。

problem 2 :祈求者

题目描述
创立之初,魔法本质上是一门记忆的艺术,有些人认为这才是其最强力的形式。它无需任何科技,也无需魔杖或者其他施法媒介,只需要你有一颗魔法师的心。在那个年代,最伟大的法师就是记忆天赋最高的人,然而魔法祈唤实在是太过艰深,因此所有的法师不得不有所专攻。即使是最刻苦的法师,将一辈子奉献给魔法,最多也只能掌握三到四个法术。然而,在那些早期的施法者中,有一个例外,一个智力超群,记忆力惊人的天才,以祈求者的名字为人们所知。在年少时,祈求者就已经掌握了不下十种法术。是的,不是四五个,也不是七个,而是十个,而且他还能毫不费力的施放这些法术。他学到过更多的法术,但是因为觉得没用,试过一次以后就彻底从脑中遗忘,这样才能为其他更为有用的法术留出空间。
祈求者能够自由操控天地间的 26 种元素:冰(Q),雷(W),火(E)……分别用二十六种大写英文字母表示,世间的魔法皆是由这些元素排列而成的。祈求者有 n 个“元素球”,每个元素球能表示 m 种不同的元素,但在施法时只有一种元素能够发挥作用。祈求者施法时会切换“元素球”所代表的元素,拼凑出咒语所需要的元素序列。每个元素球只能使用一次,即当它代表元素 X 在咒语中出现过一次时,就不能再次代表 X 和 X 以外的其他元素在咒语的另一处出现。祈求者从万神殿首领阿曼瑟尔处习得了毁灭魔法“毁天灭地”,其咒语是 k个连续的元素,用长度为 k 的字符串表示。卡尔想用他的“元素球”尽可能多的拼出这串咒语,使得他释放出的“毁天灭地”威力尽可能大。但这串咒语实在是太长了,祈求者只能尽可能多的拼凑出这串咒语的前缀(注:前缀可以为整个字符串),来增大“毁天灭地”的威力。祈求者虽然记忆力超群,但他的数学功底实在太差啦。他现在需要你的帮助,他该怎样安排元素球所代表的元素,尽可能长的拼出这串前缀呢?

输入格式
第一行,一个整数 T,表示数据组数
以下每 T 行:
第一行,一个整数 n,表示“元素球”
第 2…n + 1 行,每行一个字符串表示第 i 个元素球能够切换的元素种类,保
证字符串中的元素种类互不相同且全部为大写字母
第 n + 2 行,一个字符串,表示“毁天灭地”的咒语,全部为大写字母

输出格式
输出共 T 行,每行一个整数,表示祈求者能够拼出“毁天灭地”咒语的最长
前缀(出题人好良心啊都不让你们输出方案数,表白出题人)
上面那句是出题人自己加的…

样例输入 1
1 3 A
B
BD
AD
ADBDABA

样例输出 1
3

样例输入 2
1 3 A
CD
AB
GK
AABAGK

样例输出 2
2

样例解释 1
祈求者有三个元素球,第一个元素球可以表示元素 A 或 B,第二个元素球可
以表示元素 B 或 D,第三个元素球可以表示 A 或 D
最长能够拼出长度为 3 的前缀 ADB,其中一种可行方式为:第一个元素球
切换为 A,第二个元素球切换为 B,第三个元素球切换为 D

样例解释 2
祈求者有三个元素球,第一个元素球可以表示元素 A 或 C 或 D,第二个元
素球可以表示元素 A 或 B,第三个元素球可以表示 G 或 K
最长能够拼出长度为 2 的前缀 AA,其中一种可行方式为:第一个元素球切
换为 A,第二个元素球切换为 A,第三个元素球无法参与构成

数据规模与约定
设第 i 个元素求能表示 ai 种元素

这里写图片描述

思路
对于1-6个点,可以DFS处理。
枚举每一个位置放置哪个可能的元素球,当遇到第一个无法放置的情况便返回,枚举所有放置方案即可——匈牙利算法剔除了寻找增广路的过程。

仔细观察冷静分析后会发现,本题的最大放置关系可以转化为二分图最大匹配问题。可恶啊我一开始也没看出来….

那么我们便可以二分最大长度,然后将长度范围内每个位置向可以选择的元素球连边,做二分图匹配,看是否可完美匹配,即可验证二分。

代码——搜索版本

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define RI register intusing namespace std;int t,n,tot,len;int num[2010][2010],ban[100010];//每一个元素球可以选择的元素,标准串 int po[2010][2010];//每一个位置可以被哪些元素球填充 int siz[100010],chan[100010];//可选择元素的数量,可选择元素球的数量 char ch;bool b[100010];//是否选择过此元素球 void init(){    for(RI j=1;j<=tot;j++)//枚举位置     {        for(RI z=1;z<=n;z++)//枚举元素球         {            for(RI s=1;s<=siz[z];s++)//枚举元素             {                if(num[z][s]==ban[j])                {                    po[j][++chan[j]]=z;                    break;                }            }        }    }}void search(int k)//位置 {    len=max(len,k-1);    for(RI j=1;j<=chan[k];j++)//枚举元素球     {        if(!b[po[k][j]])        {            b[po[k][j]]=1;            search(k+1);            b[po[k][j]]=0;        }    }}int main(){    scanf("%d",&t);    for(RI i=1;i<=t;i++)    {        memset(num,0,sizeof(num));        memset(ban,0,sizeof(ban));        memset(po,0,sizeof(po));        memset(siz,0,sizeof(siz));        memset(chan,0,sizeof(chan));        memset(b,0,sizeof(b));        tot=0;//别再忘了啊         scanf("%d",&n);        for(RI j=1;j<=n;j++)        {            ch=getchar();            while(ch<'A'||ch>'Z')            ch=getchar();            while(ch>='A'&&ch<='Z')            {                num[j][++siz[j]]=(ch-'A'+1);                ch=getchar();            }        }        ch=getchar();        while(ch<'A'||ch>'Z')        ch=getchar();        while(ch>='A'&&ch<='Z')        {            ban[++tot]=(ch-'A'+1);            ch=getchar();        }        init();        len=-1e9+7;        search(1);        printf("%d\n",len);    }    return 0;}


代码——匈牙利版本

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define RI register intusing namespace std;int t,n,tot,ls,rs,len,cnt;int num[2010][2010],ban[100010];//每一个元素球可以选择的元素,标准串 int siz[100010];//可选择元素的数量char ch;int first[200010],nxt[200010]; int lkx[100010],lky[100010];bool flag;bool vis[100010];struct edge{    int u,v,w;}l[200010];void build(int f,int t){    l[++tot]=(edge){f,t};    nxt[tot]=first[f];    first[f]=tot;}void init(int k){    for(RI j=1;j<=k;j++)//枚举位置     {        flag=0;        for(RI z=1;z<=n;z++)//枚举元素球         {            for(RI s=1;s<=siz[z];s++)//枚举元素             {                if(num[z][s]==ban[j])                {                    build(j,cnt+z);//记住建单向边                     break;                }            }        }    }}int path(int k){    for(RI i=first[k];i!=-1;i=nxt[i])    {        int x=l[i].v;        if(!vis[x])        {            vis[x]=1;            if(!lky[x]||path(lky[x]))            {                lkx[k]=x;                lky[x]=k;                return 1;            }        }    }    return 0;}int check(int k){    memset(l,0,sizeof(l));    memset(first,-1,sizeof(first));    memset(nxt,0,sizeof(nxt));    memset(lkx,0,sizeof(lkx));    memset(lky,0,sizeof(lky));    init(k);    len=0;    for(RI i=1;i<=k;i++)    {        if(!lkx[i])        {            memset(vis,0,sizeof(vis));            len+=path(i);        }    }    if(len>=k)    return 1;    else return 0;}int main(){    scanf("%d",&t);    for(RI i=1;i<=t;i++)    {        memset(num,0,sizeof(num));        memset(ban,0,sizeof(ban));        memset(siz,0,sizeof(siz));        memset(first,-1,sizeof(first));        cnt=0;        scanf("%d",&n);        for(RI j=1;j<=n;j++)        {            ch=getchar();            while(ch<'A'||ch>'Z')            ch=getchar();            while(ch>='A'&&ch<='Z')            {                num[j][++siz[j]]=(ch-'A'+1);                ch=getchar();            }        }        ch=getchar();        while(ch<'A'||ch>'Z')        ch=getchar();        while(ch>='A'&&ch<='Z')        {            ban[++cnt]=(ch-'A'+1);            ch=getchar();        }        ls=0;        rs=cnt+1;        while(ls+1<rs)        {            int mid=(ls+rs)>>1;            if(check(mid))            ls=mid;            else rs=mid;        }        printf("%d\n",ls);    }    return 0;}


失误

没有初始化tot/cnt…导致多组数据标准串记录出错…..
十分显然的二分图模型没看出来….
一定要注意考虑周全…

Problem 3 :大地之灵

题目描述
地底深埋着一支兵马俑,数以万计,兵种齐全。在军队方阵前面的是考林将军的雕像,由神圣的玉石打造而成。这支军队在大地的怀抱中沉睡了上千年后,玉石雕像中,大地本身的力量经过不停的流转,不断的汇聚,已经幻化成灵,冲破了玉石的束缚。伟大的大地之灵考林从容地行走在地面之上,召唤着地底的军队,横扫一切敌人。大地之灵拥有三种颜色的灵石,他可以让两种不同颜色的灵石之间产生“直接共鸣”。这种“直接共鸣”是可以传递的,传递后称为“间接共鸣”,“间接共鸣”也可以传递。即令 a 与 b 之间产生“直接共鸣”,b 与 c 之间产生“直接共鸣”,那么 a 与 c 之间将产生“间接共鸣”。同种颜色的灵石也可以产生“直接共鸣”或“间接共鸣”,但这是及其危险的行为,自身的共鸣波频非常巨大,灵石将会受到巨大的能量冲击而损坏。幸好,每次传递,共鸣的波频会降低。如果两个同种颜色的灵石通过大于等于两个灵石产生“间接共鸣”,那么“间接共鸣”的波频会降低到一个安全的范围内,使得灵石不会受到损坏。大地之灵现在有 n 个红色灵石,m 个蓝色灵石和 k 个黄色灵石。灵石之间两两不同。每一种共鸣方案都会产生地磁之力,但每一种方案只能使用一次。大地之灵想知道他能产生多少次地磁之力,即这些灵石之间有多少种不损坏灵石的共鸣的方案。每种方案中,灵石可以处于共鸣状态下,也可以不处于共鸣状态下。两种方案不同当且仅当存在两个点,在一种方案中“直接共鸣”,而在另一种方案中没有“直接共鸣”。

输入格式
三个整数 n,m,k,表示大地之灵有 n 个红色灵石,m 个蓝色灵石和 k 个黄色灵石

输出格式
一行,表示共鸣的方案数。由于答案可能比较大,你需要输出答案除以 1e9+ 7 的方案数

样例输入 1
1 1 1

样例输出 1
8

样例输入 2
1 2 2

样例输出 2
63

样例输入 3
1 3 5

样例输出 3
3264

样例解释 1
虚线表示共鸣。三种共鸣可以选或不选,因此方案数为 2^3
这里写图片描述

样例解释 2
这里写图片描述
样例 2 的这种方案是不合法的。蓝色灵石与红色灵石产生“直接共振”,红色灵石与另一个蓝色灵石产生“直接共振”,因此两个蓝色灵石之间通过一个红色灵石产生“间接共振”,而两个蓝色灵石之间只有一个灵石传递,小于两个,所以蓝色灵石会因共鸣频率过大而损坏。

这里写图片描述
样例 2 的这种方案也是不合法的。黄色灵石与黄色灵石产生“直接共鸣”,中间没有大于等于两个灵石进行传递。

这里写图片描述

思路
分析题目后DP处理

Problem 4 :

题目描述
给你一张 n 个点,m 条边的无向图(没有重边,没有自环),每条边有一个
边权 w,输出起点为 S,终点为 E,且恰好经过 k 条边的最短路长度

输入格式
第一行:五个整数 n,m,S,E,k
第 2…m + 1 行:每行三个证书 w,u,v 表示从 u 到 v 有一条权值为 w 的无向边

输出格式
一个整数,表示从 S 到 E 恰好经过 k 条边的最短路长度

样例输入
3 3 1 3 4
1 2 2
1 3 1
2 3 4

样例输出
8

样例解释
这里写图片描述
从 1->3->1->2->3,走过 4 条边,最短路为 8

数据规模与约定
对于 30%的数据:n,m,k <= 15
对于另 20%的数据:所有 w 均为 1
对于 100%的数据: 3 <= n <= 200, 2 <= m <= 200,1 <= w <= 1000,k<=1,000,000

思路
正解是倍增folyd(DP),这里只介绍50%分数的做法。

观察数据范围。
首先我们可以发现:对于所有的边权都为1的情况,答案为k条长度为1的边边权相加,即为k本身。
那么久可以拿到20%的分数了。
然后对于前30%的数据,由于n和m都比较小,我们可以用分层图最短路解决,多开一维记录从起点走到当前点经过了多少边。
这样又可以拿到30%的分数
分层图最短路详解请见:我还没写2333

代码

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#define RI register intusing namespace std;int n,m,S,E,x,ru,rv,rw,tot;int first[200010],nxt[200010];int dis[20][500010],inq[20][500010];bool flag;struct edge{    int u,v,w;}l[200010];struct ini{    int A,Z;};queue<ini>q;void build(int f,int t,int c){    l[++tot]=(edge){f,t,c};    nxt[tot]=first[f];    first[f]=tot;}void SPFA(){    memset(dis,0x7f,sizeof(dis));    dis[S][0]=0;    inq[S][0]=1;    q.push((ini){S,0});    while(!q.empty())    {        ini k=q.front();        q.pop();        inq[k.A][k.Z]=0;        for(RI i=first[k.A];i!=-1;i=nxt[i])        {            int x=l[i].v;            if(dis[x][k.Z+1]>dis[k.A][k.Z]+l[i].w)            {                dis[x][k.Z+1]=dis[k.A][k.Z]+l[i].w;                if(!inq[x][k.Z+1])                {                    q.push((ini){x,k.Z+1});                    inq[x][k.Z+1]=1;                }            }        }    } }int main(){    memset(first,-1,sizeof(first));    scanf("%d%d%d%d%d",&n,&m,&S,&E,&x);    for(RI i=1;i<=m;i++)    {        scanf("%d%d%d",&ru,&rv,&rw);        if(rw!=1)        flag=1;        build(ru,rv,rw);        build(rv,ru,rw);    }    if(flag)    {        SPFA();        printf("%d",dis[E][x]);    }    else    {        printf("%d",x);    }    return 0;}
原创粉丝点击