这个题是真恶心……做了一上午qwq
这个题开始一看:应该是个最短路,仔细一看,有100种文化,状压不了, 企图用结构体里开个bool数组解决,仔细一想这样又使状态变少了,所以也不行
前前后后想来想去,觉得只能dfs了,但是肯定需要剪枝。我就在想剪枝的办法,最开始我是想着记忆化一下,记录下每个点到终点的最短距离,如果发现在这个点已经走过,让答案和从起点走到这的距离再加上这个点到终点比较下,然后直接返回,这样打拿了91,死活过不去tle那个点。之后又看到别人又用了a*的思想,spfa预处理了下,如果这个点之前的路径加上这个点不管限制到终点的最短路大于答案就直接返回,加上以后还是tle,最后又看到别人说要倒序搜索(直到现在我也不知道为啥这么干,大概是面向数据编程?)最后又加上了倒序。还是不行,静态调试了半天,最后发现开大空间就好了……泪牛满面。
虽然挺折腾,不过还是长进挺大的……至少最后做到了尽可能完美,0ms,跑到灰常快233333333
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; struct in { int to,ne,co; }ter[10010],es[10010]; int n,k,m,s,e,x,y,z,t1,t2,ans[110],cul[110],h1[110],h2[110],dis[110]; bool flag[110],used[110],se[110][110]; inline void b2(int f,int l) { es[++t2]=(in){l,h2[f],1},h2[f]=t2; } inline void b1(int f,int l,int c) { ter[++t1]=(in){l,h1[f],c},h1[f]=t1; ter[++t1]=(in){f,h1[l],c},h1[l]=t1; } void dfs(int x,int v) { if(x==s)//如果到起点,直接返回 return; if(v>dis[e])//答案偏大,返回 return; if(v+ans[x]>dis[e])//答案偏大,返回 return; for(int i=h1[x];i>0;i=ter[i].ne) { int t=ter[i].to; if(flag[cul[t]]||!used[t])//如果这个点的文化之前学过,或者这个点压根不能到终点,跳过它 continue; flag[cul[t]]=1; bool f=0; if(v+ter[i].co+ans[t]>dis[e])//ans数组存的是不管限制的最短路,真实情况一定不小于它 continue; for(int j=h2[cul[t]];j>0;j=es[j].ne) { if(flag[ter[j].to])//有一个不行就退出 { f=1;break; } } if(f) { flag[cul[t]]=0; continue; } if(dis[t]<dis[109])//如果这个点之前走过,直接得出答案 { dis[e]=min(dis[e],v+ter[i].co+dis[t]);flag[cul[t]]=0;return; } dfs(t,v+ter[i].co);//否则走一遍 dis[x]=min(dis[x],ter[i].co+dis[t]); dis[e]=min(dis[e],dis[x]+v); flag[cul[t]]=0; } return; } queue<int>qwq; inline void spfa()//记录下所有点到起点的距离 { ans[s]=0; qwq.push(s); flag[s]=1; while(!qwq.empty()) { int qaq=qwq.front(); for(int i=h1[qaq];i>0;i=ter[i].ne) { int t=ter[i].to; if(ans[t]>ans[qaq]+ter[i].co) { ans[t]=ans[qaq]+ter[i].co; if(!flag[t]) qwq.push(t),flag[t]=1; } } qwq.pop(); flag[qaq]=0; } } inline void bfs() { qwq.push(e); used[e]=1; while(!qwq.empty()) { int qaq=qwq.front(); for(int i=h1[qaq];i>0;i=ter[i].ne) { int t=ter[i].to; if(!used[t]) used[t]=1,qwq.push(t); } qwq.pop(); } } int main() { freopen("wenhua.in","r",stdin); freopen("wenhua.out","w",stdout); memset(dis,127/3,sizeof(dis)); memset(ans,127/3,sizeof(ans)); memset(h1,-1,sizeof(h1)); memset(h2,-1,sizeof(h2)); scanf("%d%d%d%d%d",&n,&k,&m,&s,&e); for(int i=1;i<=n;i++) scanf("%d",&cul[i]); for(int i=1;i<=k;i++) for(int j=1;j<=k;j++) { scanf("%d",&x); if(x==1) b2(i,j),se[i][j]=1; } for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); if(!se[x][y]) b1(x,y,z); } spfa();//预处理一遍估价函数 bfs();//判断哪些点能够到达终点(一个小剪枝) dis[s]=0; int j=h2[65]; flag[cul[e]]=1; if(ans[s]>dis[109])//如果起点直接跑不到终点,输出-1 { cout<<-1;return 0; } dfs(e,0); if(dis[e]<dis[109])//如果小于初始值,说明可以到 cout<<dis[e]<<'\n'; else cout<<-1; fclose(stdin); fclose(stdout); return 0; }