洛谷 P7551 [COCI2020-2021#6] Alias

54f07ce529cf4918af53d6b4f9186f65.png

e0754db9bf824165b1b348b9f4a1d795.png


 样例有点多就不截图了,这道题导致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;
}

e3dd046306e94654afd62283bf2f1f2c.png

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的全部最短路都求出来了.

所以可以用堆来优化选点
因为每次都要走目前的最短路去更新之后的路才能保证算法的正确性,如括号中所述.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值