【题目描述】题目
【题意】中文题目,题意就不解释了
【分析】用dis[u][x]表示到达u点,飞行符状态为x所需的最少时间。假设x=0表示飞行符未使用过,x=1表示已经使用过一次,x=2表示用过两次,很显然,x=0的状态,能转移到x=1(用一次)和x=0(不用),x=1的状态只能转移到x=2(再用一次或者不用了),x=2的状态只能转移到x=2(必须的)。最后从dis[1][0]状态开始,跑一次spfa,输出min(dis[n][0],dis[n][1],dis[n][2])即可。
【AC代码】
#include<stdio.h> #include<string.h> #include<vector> #include<queue> #include<map> #include<set> #include<stdlib.h> #include<algorithm> #define maxn 1100 #define LL long long using namespace std; #define inf 1e17 LL num,p[maxn],n; struct node { LL st,en,next,len; }E[maxn*maxn]; void init() { num=0; memset(p,-1,sizeof(p)); } void add(LL st,LL en,LL len) { E[num].st=st; E[num].en=en; E[num].len=len; E[num].next=p[st]; p[st]=num++; } struct Node { LL dis,id,flog; }; LL dis[maxn][3]; bool vis[maxn][3]; void solve() { for(LL i=1;i<=n;i++) for(LL j=0;j<3;j++) dis[i][j]=inf,vis[i][j]=0; queue<Node> q; Node st,en; st.dis=0,st.id=1,st.flog=2; q.push(st); vis[1][2]=1; dis[1][2]=0; while(q.size()) { st=q.front(); q.pop(); for(LL i=p[st.id];i!=-1;i=E[i].next) { en.id=E[i].en; if(st.flog>=1) { en.dis=st.dis; en.flog=st.flog-1; if(dis[en.id][en.flog]>en.dis) { vis[en.id][en.flog]=1; dis[en.id][en.flog]=en.dis; q.push(en); } en.dis=st.dis+E[i].len; if(st.flog==2) en.flog=2; else if(st.flog==1) en.flog=0; if(dis[en.id][en.flog]>en.dis) { vis[en.id][en.flog]=1; dis[en.id][en.flog]=en.dis; q.push(en); } } else if(st.flog==0) { en.dis=st.dis+E[i].len; en.flog=0; if(dis[en.id][en.flog]>en.dis) { vis[en.id][0]=1; dis[en.id][en.flog]=en.dis; q.push(en); } } } } } int main() { while(scanf("%lld",&n)==1) { init(); for(LL i=1;i<=n;i++) for(LL j=1;j<=n;j++) { LL x; scanf("%lld",&x); if(x==0) continue; add(i,j,x); } solve(); LL ans=inf; for(LL i=0;i<3;i++) ans=min(ans,dis[n][i]); if(ans==inf) puts("-1"); else printf("%lld\n",ans); } return 0; }