CodeForces-238E-Meeting Her

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xbb224007/article/details/83687150

(一)题面:

题目连接:CodeForces - 238E-Meeting Her

Urpal lives in a big city. He has planned to meet his lover tonight.

The city has n junctions numbered from 1 to n. The junctions are connected by m directed streets, all the roads have equal length. Urpal lives in junction a and the date is planned in a restaurant in junction b. He wants to use public transportation to get to junction b. There are k bus transportation companies. At the beginning of every second, a bus from the i-th company chooses a random shortest path between junction si and junction ti and passes through it. There might be no path from si to ti. In that case no bus will leave from si to ti. If a bus passes through a junction where Urpal stands, he can get on the bus. He can also get off the bus at any junction along the path.

Now Urpal wants to know if it's possible to go to the date using public transportation in a finite amount of time (the time of travel is the sum of length of the traveled roads) and what is the minimum number of buses he should take in the worst case.

At any moment Urpal knows only his own position and the place where the date will be. When he gets on the bus he knows only the index of the company of this bus. Of course Urpal knows the city map and the the pairs (si, ti) for each company.

Note that Urpal doesn't know buses velocity.

Input

The first line of the input contains four integers nmab (2 ≤ n ≤ 100; 0 ≤ m ≤ n·(n - 1); 1 ≤ a, b ≤ na ≠ b).

The next m lines contain two integers each ui and vi (1 ≤ ui, vi ≤ nui ≠ vi) describing a directed road from junction ui to junction vi. All roads in the input will be distinct.

The next line contains an integer k (0 ≤ k ≤ 100). There will be k lines after this, each containing two integers si and ti(1 ≤ si, ti ≤ nsi ≠ ti) saying there is a bus route starting at si and ending at ti. Please note that there might be no path from si to ti, this case is described in the problem statement.

Output

In the only line of output print the minimum number of buses Urpal should get on on his way in the worst case. If it's not possible to reach the destination in the worst case print -1.

Examples

input

7 8 1 7
1 2
1 3
2 4
3 4
4 6
4 5
6 7
5 7
3
2 7
1 4
5 7

output

2

(二)题意:

给定一个有n(n<100)个点的有向图以及k(k<100)个公交车,每辆车ki有一个起点si和终点ti,公交车ki从起点si到ti的路径会随机选择一条最短路(如果si不能到达ti则该车不会出发)。现给你的起点S和目标点T,问你从S点到T点的过程中:最坏的情况下最少需要搭多少辆车(最坏情况下不能到达则输出-1)。你可以在所搭车途经的任何一个点下次,也可以在车途径的任何点(你当前在该点)上车。

 

(三)题解:

①先说一下我开始的思路:对于一辆车ki的起点si和终点ti,我们先求出ki从si到ti的路径中必须经过的点,如果必须经过的点有(si,ai,bi,ti),那么我们在一个新图中加边(si->ai,si->bi,si->ti,a1->bi,ai->ti,bi->ti,边权全为1),我们对所有的车做同样的处理,然后对于最后得到的新图跑一遍Floyd就求出了si到ti的最短距离,也就是最少需要搭车的数目。然而写完以后一直WA,接着在CF看到一组数据,画成图如下所示:

按照上述的建图方法,我们显然会得到无解的情况。但是实际上虽然从(1->4)的路径中必经点只有1和4,但是对于非必经点2和3而言都是其余的车的必经点,故也可以到到达终点。所以单单考虑每一辆车的必经点是不够的(然后自闭qwq)。

②下面来说一下正解吧:

设dp[i]为点i到终点的最优解。

首先枚举每一辆车ki,再枚举每一辆车的必经点ai(也就是从必经点ai搭上车ki),从ai开始沿着ki可能经过的最短路进行搜索,取所有路径上的解的最大值,如果得到的最终的结果tmp<dp[ai],那么更新dp[ai]=tmp。

重复上述过程(如果某一个必经点被更新了,那么需要继续枚举所有车辆的必经点),直到所有车的必经点都无法再被更新,这时dp[S]也就是最终结果。

算法的正确性是显然的(最终所有的必经点都不能再被更新,且每一辆车的所有可能的路径都已考虑--取max),再分析一下时间复杂度:每一个点最多被更新n次,每次更新O(n)地遍历整个图,每次枚举O(k*n),故总的复杂度为O(k*n^3),然而实际上跑得很快。 

③再简单说一下一点细节:

对于求必经点的部分,我的做法是先求了si到ti的最短路(Dijkstra)并记录路径,然后枚举删除路径上的每一个点,如果删除后最短路径长度变长,说明该点是必经点(复杂度O(m*nlogn))。然而后面发现在<从ai开始沿着ki可能经过的最短路进行搜索>时,需要用Floyd预处理任意两点间的距离,而用Floyd跑的结果也可以求必经点(并且网上基本都是这么写的,我估计脑子有坑吧)。

 

(四)代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=105;
vector<int>G1[maxn];
int n,m,a,b,q,mp[maxn][maxn],must[maxn][maxn];
int dist[maxn],vis[maxn],p[maxn],fb[maxn],tb[maxn],dp[maxn],Md[maxn];
struct Heap{
    int u,d;
    Heap(int _u=0,int _d=0){
        u=_u;d=_d;
    }
    bool operator < (const Heap &H)const{
        return d>H.d;
    }
};
int Dijkstra(int s,int t,int del){
    if(s==del||t==del)return INF;
    memset(vis,0,sizeof vis);
    for(int i=1;i<=n;i++)dist[i]=INF;
    dist[s]=0;p[s]=-1;
    priority_queue<Heap>Q;
    Q.push(Heap(s,0));
    while(!Q.empty()){
        Heap o=Q.top();Q.pop();
        int u=o.u;
        if(vis[u])continue;
        vis[u]=1;
        for(int i=0;i<G1[u].size();i++){
            int v=G1[u][i];
            if(v==del)continue;
            if(dist[v]>dist[u]+1){
                dist[v]=dist[u]+1;
                Q.push(Heap(v,dist[v]));p[v]=u;
            }
        }
    }
    return dist[t];
}
vector<int>road;
int solve(int u,int k,int t){
    if(vis[u]==t)return Md[u];
    int tmp=-1,sz=G1[u].size();
    vis[u]=t;
    for(int i=0;i<sz;i++){
        int v=G1[u][i];
        if(mp[fb[k]][u]+1+mp[v][tb[k]]==mp[fb[k]][tb[k]]){
            tmp=max(tmp,solve(v,k,t));
        }
    }
    return Md[u]=min(tmp==-1?INF:tmp,dp[u]);
}
int main(){
    #ifdef DanDan
    freopen("in.txt","r",stdin);
    #endif // DanDan
    int u,v,mv,md;
    memset(mp,0x3f,sizeof mp);
    scanf("%d%d%d%d",&n,&m,&a,&b);
    for(int i=1;i<=n;i++)mp[i][i]=0;
    for(int i=0;i<m;i++){
        scanf("%d%d",&u,&v);
        G1[u].push_back(v);mp[u][v]=1;
    }
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
            }
        }
    }
    scanf("%d",&q);
    for(int bs=1;bs<=q;bs++){
        scanf("%d%d",&u,&v);
        int d=Dijkstra(u,v,-1);mv=v;
        fb[bs]=u;tb[bs]=v;
        if(d==INF)continue;
        while(v>0){
            road.push_back(v);v=p[v];
        }
        int sz=road.size();
        for(int i=sz-1;i>=0;i--){
            int d1=Dijkstra(u,tb[bs],road[i]);
            if(d1>d)road.push_back(road[i]);
        }
        road.erase(road.begin(),road.begin()+sz);sz=road.size();
        for(int i=0;i<sz;i++)must[bs][road[i]]=1;road.clear();
    }
    int Update=1,times=1;
    memset(vis,0,sizeof vis);
    memset(dp,0x3f,sizeof dp);dp[b]=0;
    while(Update--){
        for(int bs=1;bs<=q;bs++)
            for(int i=1;i<=n;i++)
                if(must[bs][i]){
                    int tmp=solve(i,bs,times++)+1;
                    if(tmp<dp[i])Update=1,dp[i]=tmp;
                }
    }
    printf("%d\n",dp[a]==INF?-1:dp[a]);
    return 0;
}

 

(五)总结:

开始想得好好的,然而看到那一组卡的数据以后就开始自闭没什么想法了≡(▔﹏▔)≡。

回想一下,感觉就是一个暴力题...

猜你喜欢

转载自blog.csdn.net/xbb224007/article/details/83687150
今日推荐