这道题前前后后做了一周虽然不是每天都想,但也算是做得最久的一道题了
先是暴力版代码,可以直接看正解
cjsj指重建时间,xw是询问,czjl指村庄距离,dd记录村庄是否重建完毕,ts是当前天数,jl指当前到了第几次询问
#include<iostream>
#include<string.h>
using namespace std;
int m,n,q;
int cjsj[207];
int xw[50007][4];
int czjl[207][207];
bool dd[207];
int jl;
int ts;
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>cjsj[i];
memset(czjl,0x3f,sizeof(czjl));//先初始化为一个很大的值
for(int i=0;i<m;i++)
{
int x,y,z;
cin>>x>>y>>z;
czjl[x][y]=z;
czjl[y][x]=z;
}
cin>>q;
for(int i=0;i<q;i++)
cin>>xw[i][1]>>xw[i][2]>>xw[i][3];
while(jl<q)
{
memset(dd,false,sizeof(dd));//假设全部没有重建完
for(int i=0;i<n;i++)
if(cjsj[i]<=ts)dd[i]=true;//重建好了
while(xw[jl][3]==ts)//到了这一天
{
if(!dd[xw[jl][1]]||!dd[xw[jl][2]])cout<<-1<<endl;//如果起点或终点没有重建好,之间输出-1
else//否则就跑最短路
{
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(dd[i]&&dd[j]&&dd[k])
czjl[i][j]=min(czjl[i][j],czjl[i][k]+czjl[k][j]);
if(czjl[xw[jl][1]][xw[jl][2]]==0x3f3f3f3f)cout<<-1<<endl;//距离还是初值,证明无法到达
else cout<<czjl[xw[jl][1]][xw[jl][2]]<<endl;//否则可以到达
}
jl++;//进行下一次询问
}
ts++;//下一天
}
return 0;
}
朴素算法,可以拿20分
没错只有20分
吸氧+关闭同步(就是优化cin/cout的时间)可以拿50分
下面是正解
在此还要谢谢 @生而为人
cjsj指重建时间,xw是询问,czjl指村庄距离,dd记录村庄是否重建完毕,cz是当前到了第几个村庄
每次询问时就判断,当前村庄是否已经重建完毕?如果是,就用它跑一次Floyd(把它作为中转点),且切换到下一个村庄继续判断;如果不是,就跳过最短路部分
这可以满足,这样情况下,每次输出的一定是最优情况
#include<iostream>
#include<string.h>
using namespace std;
int m,n,q;
int cjsj[207];
int xw[50007][4];
int czjl[207][207];
int cz;
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>cjsj[i];
memset(czjl,0x3f,sizeof(czjl));
for(int i=0;i<m;i++)
{
int x,y,z;
cin>>x>>y>>z;
czjl[x][y]=z;
czjl[y][x]=z;
}
cin>>q;
for(int i=1;i<=q;i++)
{
cin>>xw[i][1]>>xw[i][2]>>xw[i][3];//到这里为止都是一样的
while(cjsj[cz]<=xw[i][3]&&cz<n)//记住要<n,不然会卡死
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
czjl[i][j]=min(czjl[i][j],czjl[i][cz]+czjl[cz][j]);//最短路部分
cz++;//下一个村庄
}
if(cjsj[xw[i][1]]>xw[i][3]||cjsj[xw[i][2]]>xw[i][3])cout<<-1<<endl;
else if(czjl[xw[i][1]][xw[i][2]]==0x3f3f3f3f)cout<<-1<<endl;
else cout<<czjl[xw[i][1]][xw[i][2]]<<endl;
} //这部分与上面是一样的
return 0;
}