样例有点多就不截图了,这道题导致WA的点还是挺多的。
设有映射f为unordered_map<string,int>f
有一字符串为x
1.判断字符串是否存在不可以写成
if(f[x])cout<<x<<"存在";
必须要用if(f.count(x))cout<<x<<"存在";
或者if(f.find(x)!=f.end())cout<<x<<"存在";
否则会出现未知错误(没搞明白是什么)
2.定义的邻接表long long e[n][n] 输入的时候不可以 int t, e[1][1]=t ,会出错。
明明输入数据是INT范围内的, 不知道为什么会出错。
3.给数值设置无穷大的时候应参考最长路。比如最长路是1000,那无穷大至少要1001。
此处定义long long e[n][n]的话可以简单赋值为e[i][j]=LONG_LONG_MAX/2;
搞清楚这些点之后这道题就很好做了,不用直接给字符串建立邻接表,将字符串映射成我们习惯的整数再建立邻接表就可以了。
n的最大值1000,询问的次数q最大值1000。
那么易得floyd算法复杂度至少是1e9(10亿)
dijkstra堆优化算法复杂度至少是1e6*log(1e3)(1000万)
所以理论上来说floyd是过不了的。
TLE代码(Floyd)
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
int n,m,fcnt,q;
string x,y,a,b;
unordered_map<string,int>f;//给字符串建立整数映射
ll e[1001][1001],t;
inline void scan(){
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
e[i][j]=LONG_LONG_MAX/2;
}
}
for(int i=1;i<=m;i++){
cin>>x>>y>>t;
if(!f.count(x))f[x]=++fcnt;
if(!f.count(y))f[y]=++fcnt;
e[f[x]][f[y]]=min(e[f[x]][f[y]],t);
}
}
inline void floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
e[i][j]=min(e[i][j],e[i][k]+e[k][j]);
}
}
}
}
int main(){
scan();
floyd();
cin>>q;
for(int i=1;i<=q;i++){
cin>>a>>b;
if(e[f[a]][f[b]]==LONG_LONG_MAX/2)cout<<"Roger"<<endl;
else cout<<e[f[a]][f[b]]<<endl;
}
return 0;
}
AC代码(Dijkstra+堆优化选点)
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using pli=pair<ll,int>;
const int MAXN=1e3+1;
const ll MAX=LONG_LONG_MAX/2;
priority_queue<pli,vector<pli>,greater<pli>>pq;//距离->编号
unordered_map<string,int>f;//字符串映射为整数
vector<pli>e[MAXN];//距离->编号
bitset<MAXN>vis;
int n,m,fcnt,q;
string x,y,a,b;
ll t,dist[MAXN];
inline void scan(){
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>x>>y>>t;
if(!f.count(x))f[x]=++fcnt;
if(!f.count(y))f[y]=++fcnt;
e[f[x]].push_back({t,f[y]});
}
}
inline void dijkstra(int k){//k点开始的最短路
vis.reset();
for(int i=1;i<=n;i++)
dist[i]=MAX;
dist[k]=0;
pq.push({0,k});
while(!pq.empty()){
int now=pq.top().second;
pq.pop();
if(vis[now])continue;
vis[now]=true;
for(auto i:e[now]){
int nxt=i.second;ll toNxt=i.first;
dist[nxt]=min(dist[nxt],dist[now]+toNxt);
if(!vis[nxt])
pq.push({dist[nxt],nxt});
}
}
}
int main(){
scan();
cin>>q;
for(int i=1;i<=q;i++){
cin>>a>>b;
dijkstra(f[a]);
if(dist[f[b]]==MAX)cout<<"Roger"<<endl;
else cout<<dist[f[b]]<<endl;
}
return 0;
}
关于Dijkstra算法的一些感想.
定义s为起点,e为其他点,dist数组为s->e的最短距离,pre代表前一个点.
[
为了得到s->e的最短距离,势必要先得到s->pre(e)的最短距离
但是pre(e)->e可能不止一条路,所以用dist[pre(e)]+pre(e)->e一直去更新最短路dist[e]即可.
]
dj算法为了方便起见就把s->e的全部最短路都求出来了.
所以可以用堆来优化选点
因为每次都要走目前的最短路去更新之后的路才能保证算法的正确性,如括号中所述.