当前位置: 代码迷 >> 综合 >> HDU 4014 Jimmy’s travel plan(unordered_map暴力)
  详细解决方案

HDU 4014 Jimmy’s travel plan(unordered_map暴力)

热度:55   发布时间:2023-12-22 14:09:51.0

题意:

给定一个n点m边的无向图,点的编号为[1,n],边权均为1,可能含有重边。

Q次询问,每次询问给出两个点的编号u、v,若u、v之间最短距离小于等于2,则先输出最短距离,再输出最短距离的方案数,否则输出指定字符串。

题目链接

题解:

在省赛前的训练赛中遇到了这道题,场上看这个奇怪的要求有想过bfs、dp之类的,感觉都没办法做。

第二天晚上补题的时候,在实验室门口来回踱步数十分钟,突然就悟了(雾

首先我们使用unordered_map来存邻接矩阵,其中G[u][v]的值表示u和v直接相连的边的条数,这样对邻接点的查询可以认为是常数级别的。

下面开始进入正题,考虑查询部分。

由题意可知,答案根据最短距离可分为四类:0、1、2、其他。

设查询两点编号为u、v

若u == v

    0:最短距离为0,路径数为1

若u != v

    若u的邻接点中包含v

          1:最短距离为1,路径数为G[u][v]

    否则先看(u、v)最短距离是否为2

        枚举G[u].size()和G[v].size()中较小的点的邻接点,在另一点的邻接点中查询

        设存在k个点是二者的邻接点,若k=0,则说明不存在最短距离为2的路径,输出指定字符串;

        若k>0,点分别为,则最短距离为2,路径数为。

易知最短距离为0时,判断u==v求解复杂度为O(1)

最短距离为1时,通过unordered_map所存的邻接矩阵查询,求解复杂度也为O(1)

最短距离不为0或1时,单次复杂度为二者中邻接点较少的邻接点数,这样最坏情况可能高达m*q,貌似并没有什么卵用。这里就是本题的重点了。

考虑把每次查询的答案也用一个unordered_map存下来,这样可以保证已经查询过的点对可以O(1)得到答案。

 假设所有查询点对最短距离均至少为2,能构造的最坏情况:

    1.每次查询的点对都不相同;

    2.所有 被查询的点对中邻接点size较小的 size和尽可能大。

首先考虑每次查询的点对都不相同,,说明我们只需要大约个点即可满足1。

然后通过将m条边平分来使得满足情况2,则每个点邻接点至多约为,则最坏情况下的时间复杂度约为。

因此在用unordered_map存下查询的答案后,本题的时间复杂度可以做到。

至此,本道题就做完了。

(PS:感觉这种算对时间复杂度然后暴力的题在比赛中不算少见,可见优雅的暴力也是ACMer的必备技能啊~

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define m_p make_pair
const int maxn = 1e5+5;
int t,n,m,q,u,v,x,y;
unordered_map<int,int> ans[maxn],G[maxn];//G存邻接矩阵,ans存查询的最短距离 ,3表示除了【0,2】 
unordered_map<int,ll> ans1[maxn];//ans1存查询的路径条数,理论上路径条数可能超出int范围 
int main(){
//    freopen("in.txt","r",stdin);unordered_map<int,int>::iterator it1;scanf("%d",&t);for(int cas=1;cas<=t;cas++){for(int i=1;i<maxn;i++) G[i].clear(),ans[i].clear(),ans1[i].clear();scanf("%d %d",&n,&m);for(int i=1;i<=m;i++){scanf("%d %d",&u,&v);if(u==v) continue;if(G[u].find(v)==G[u].end()) G[u].insert(m_p(v,1)),G[v].insert(m_p(u,1));else G[u][v]++,G[v][u]++;}scanf("%d",&q);cout<<"Case #"<<cas<<":\n";for(int i=1;i<=q;i++){scanf("%d %d",&u,&v);if(u>v) swap(u,v); if(ans[u].find(v)==ans[u].end()){//若此查询第一次出现 if(u==v) ans[u].insert(m_p(v,0)),ans1[u].insert(m_p(v,1));else if(G[u].find(v)!=G[u].end()) ans[u].insert(m_p(v,1)),ans1[u].insert(m_p(v,G[u][v]));else{x=u,y=v;if(G[x].size()>G[y].size()) swap(x,y);for(auto it=G[x].begin();it!=G[x].end();it++){//枚举size较小的x的邻接点 if((it1=G[y].find(it->first))!=G[y].end()){//在y的邻接点中查询 if(ans[u].find(v)==ans[u].end()) ans[u].insert(m_p(v,2)),ans1[u].insert(m_p(v,1ll*(it->second)*(it1->second)));else ans1[u][v]+=1ll*(it->second)*(it1->second);}}if(ans[u].find(v)==ans[u].end()) ans[u].insert(m_p(v,3));}}if(ans[u][v]==3) cout<<"The pair of cities are not connected or too far away.\n";else cout<<ans[u][v]<<" "<<ans1[u][v]<<"\n";}}return 0;
}

 

  相关解决方案