题意:
就是给你n个十字路口,每个路口有四个方向,按逆时针给你路口的标号,如果是0标号代表没有路口。然后你每次在路口进行右转是不花费的,然后前进,左转,倒头,都是花费1。先在你在A路口对着B路口的路上,让你走到在C路口对着D路口的路上。问你最少的花费。你面对的方向是不用的,A对B和B对A是不一样的。
思考:
其实这题,给你的路口,也没给你指定的方向,只是逆序的给你。如果按路口跑最短路会发现这个图不好弄。所以要按边跑,也就是把边看成点,把这些边看成不同的点,进行hash。怎么想到呢,因为问的就是从这个路走到那个路的花费,所以把路看成点比较好做。建图的时候就是枚举一个路口的四个路口,然后找出两个路口,对他们建图,如果是右转那么不花费。
然后值得注意的呢是,用map<PII,int>哈希会超时,那么换成unordered_map<PII,int,cmp>。这个cmp重载用法不一样也会有的超时有的不超。当然最保险的是可以不建图,直接跑,跑的时候枚举到哪就行了。哈希的时候把边哈希成特别大的值再放到unordered_map<int,int>就可以了。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define db double
#define int long long
#define PII pair<int,int >
#define mem(a,b) memset(a,b,sizeof(a))
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int mod = 1e9+7,inf = 1e18;
const int N = 5e6+10,M = 2010;
int T,n,m,k;
int va[N][4];
int dist[N],vis[N];
struct cmp{
int operator()(PII A)const{
return A.fi*521417+A.se;
}
};
int cnt;
unordered_map<PII,int,cmp> mp;
vector<PII > e[N];
void distra(int A)
{
for(int i=1;i<=cnt;i++) dist[i] = inf;
priority_queue<PII,vector<PII>,greater<PII> > q;
q.push({0,A});
dist[A] = 0;
while(q.size())
{
auto t = q.top();q.pop();
int now = t.se,dis = t.fi;
if(vis[now]) continue;
vis[now] = 1;
for(auto tt:e[now])
{
int spot = tt.fi,w = tt.se;
if(dist[spot]>dist[now]+w)
{
dist[spot] = dist[now]+w;
q.push({dist[spot],spot});
}
}
}
}
signed main()
{
IOS;
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=0;j<4;j++)
{
cin>>va[i][j];
if(!va[i][j]) continue;
int a = i,b = va[i][j];
if(!mp[{a,b}]) mp[{a,b}] = ++cnt;
if(!mp[{b,a}]) mp[{b,a}] = ++cnt;
}
for(int j=0;j<4;j++)
{
if(!va[i][j]) continue;
for(int k=0;k<4;k++)
{
if(!va[i][k]) continue;
int a = va[i][j],b = i,c = va[i][k],w = 1;
if((j+1)%4==k) w = 0;
int x = mp[{a,b}],y = mp[{b,c}];
e[x].pb({y,w});
}
}
}
int A,B,C,D;
cin>>A>>B>>C>>D;
distra(mp[{A,B}]);
if(dist[mp[{C,D}]]==inf) cout<<-1;
else cout<<dist[mp[{C,D}]];
return 0;
}
总结:
多多尝试把,我感觉map不行的时候,unordered也不行,就不想写了。一点一点优化,也许最后就过了。