【题目描述】题目
【题意】中文题目,题意就不解释了
【分析】用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;
}