神奇A题系列。。。。。。
本来以为这个题是个 网络流 或者其他 神奇的多项式算法的题,于是就一直没有想出来。。。。。。
然后再想想。。。边数点数同阶。都是不超过200的,,,说不定搜一搜剪剪枝就过了呢233333
因为之前有了UVA12035那个题的多达接近十种剪枝的磨练(那些剪枝加起来想了几个月。。。。),所以对于本题的剪枝就是小菜一碟了23333
第一个剪枝:首先只需要保留和1,2点同属于一个强连通分量的点(如果1和2不在同一强连通分量那么无解,但是本题好像并没有这样的数据),这个的话随便跑个tarjan就好了。
然后可以发现,如果确定了1到2的路径的话,那么再从2到1就是一个点权是0或1的最短路问题了。出现在之前1到2路径上的点的点权是0,其他的点权是1。
虽然点权不是都一样的,但是依然可以直接bfs出来,因为有0这个特殊的点权啊2333,一个双端队列就解决了。
所以这一部分就直接降成O(1所在强连通分量的大小)。
第二个剪枝:按理说我们是要搜出1到2的所有路径的,每搜到一条就bfs一遍更新答案。但是如果当前搜到一半的路径经过的点数 已经大于 之前的最小答案,直接剪掉(最优性剪枝)。
一个奇奇怪怪不知道有没有用的剪枝:按理说我们应该是优先搜1到2经过点数少的路径,然后bfs。但是这样不一定是更优的,极有可能被卡(其实是我懒得预处理dist 23333),所以在搜路径的时候,我是random_shuffle的路径后继端点。
这样做的好处是很快就能搜到一个正常的答案,不容易被数据卡,从而避免了很多不必要的搜索;坏处是搜到最后的答案是需要一定时间的(但从评测来看还好啦)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define pb push_back
const int maxn=205;
stack<int> s;
int H,T,q[maxn*23];
int hd[maxn],ne[maxn],to[maxn],dc,lt[maxn];
int num,n,m,d[maxn],dfn[maxn],low[maxn],k,ans=1<<30;
inline void add(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num;}
bool v[maxn],can[maxn];
void tarjan(int x){
dfn[x]=low[x]=++dc,s.push(x);
for(int i=hd[x];i;i=ne[i])
if(!dfn[to[i]]) tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
else if(!lt[to[i]]) low[x]=min(low[x],dfn[to[i]]);
if(low[x]==dfn[x]){
k++;
for(int c=s.top();;c=s.top()){
lt[c]=k,s.pop();
if(c==x) break;
}
}
}
inline int calc(){
q[H=T=1000]=2,memset(d,-1,sizeof(d)),d[2]=0;
int x;
while(H<=T){
x=q[H++];
for(int i=hd[x];i;i=ne[i]) if(can[to[i]]&&d[to[i]]<0){
if(v[to[i]]) d[to[i]]=d[x],q[--H]=to[i];
else d[to[i]]=d[x]+1,q[++T]=to[i];
}
}
return d[1];
}
void dfs(int x,int y){
if(y>=ans) return;
if(x==2){ ans=min(ans,y+calc()); return;}
vector<int> g;
for(int i=hd[x];i;i=ne[i]) if(can[to[i]]&&!v[to[i]]) g.pb(to[i]);
random_shuffle(g.begin(),g.end());
for(int i=g.size()-1,o;i>=0;i--){
o=g[i],v[o]=1;
dfs(o,y+1),v[o]=0;
}
}
int main(){
scanf("%d%d",&n,&m);
int uu,vv;
for(int i=1;i<=m;i++) scanf("%d%d",&uu,&vv),add(uu,vv);
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
if(lt[1]!=lt[2]){ puts("-1"); return 0;}
for(int i=1;i<=n;i++) if(lt[i]==lt[1]) can[i]=1;
v[1]=1,dfs(1,1);
cout<<ans<<endl;
return 0;
}