Codeforces Round #625 (Div. 2, based on Technocup 2020 Final Round) D

题意:

有一个n个点m条边的有向图。给出一条其中路径经过k个点(k个不重复的点)

起点是s,终点是t。在这个路径上的每个点时,导航系统都会给出这个点到t的其中一条最短路;

如果这条最短路的下一个点 与 给出的路径下一个点不一样需要修改成到下一个点的位置,求最少的修改次数和最多的修改次数。

样例
6 9(6个点,9条边) 1 5 5 4 1 2 2 3 3 4 4 1 2 6 6 4 4 2 4(k个点,其中之一的路径) 1 2 3 4
输出
1 2


因为1-4的最短路是1-5-4,所以1-2修改,因为2-4的最短路有两条系统可能给2-3-4或者2-6-4,所以最小修改是1,最大修改是2

思路:
因为需要要k个点到t最短路(有向图),所以用bfs跑t到所有点的最短距离;
这些点(假设x)是否存在t到x点最短路径不同情况。如果有不同情况(如同样例2-4有两个可能)最大修改++;
如果存在k个点之中相邻的两个不是最短路连接的(如同样例5-1,而k个点之中时2-1),那么最大和最小修改都要++。


#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
#define it register int
#define inf 0x3f3f3f3f
#define lowbit(x) (x)&(-x)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 998244353
const int maxn=2e5+10;
struct node{
    int v,next;
}a[maxn];
vector<int>pan[maxn];
struct node1{
    int x,bu;
    node1(){}
    node1(int xx,int buu):x(xx),bu(buu){}
    friend bool operator<(const node1 a,const node1 b){
        if(a.bu==b.bu){return a.x>b.x;}
        return a.bu>b.bu;
    }
};
int head[maxn],cnt,n,m,k,minnge,minbu,b[maxn],f,bu[maxn],ci[maxn];
il void add(int v,int w){
    a[cnt].v=w;a[cnt].next=head[v];
    head[v]=cnt++;
}
il void bfs(int u,int buu){
    bu[u]=0;
    priority_queue<node1>q;
    q.push(node1(u,buu));
    while(!q.empty()){
        node1 tt=q.top();q.pop();
        int w=tt.x,bu2=tt.bu+1;
        for(it i=head[w];~i;i=a[i].next){
            int v=a[i].v;
            if(bu[v]==-1){
                ci[v]++;bu[v]=bu2;pan[v].push_back(w);q.push(node1(v,bu2));
            }
            else if(bu[v]==bu2){
                ci[v]++;pan[v].push_back(w);
            }
        }
    }
}
il bool pand(int u,int v){
    for(auto &i:pan[u]){
        if(i==v){return true;}
    }
    return false;
}
int main(){
    mem(head,-1);mem(bu,-1);
    scanf("%d%d",&n,&m);
    for(it i=0;i<m;i++){int v,w;
        scanf("%d%d",&v,&w);
        add(w,v);
    }
    scanf("%d",&k);
    int ma=0,mi=0;
    for(it i=0;i<k;i++){
        scanf("%d",&b[i]);
    }
    bfs(b[k-1],1);
    for(it i=0;i<k-1;i++){
        if(!pand(b[i],b[i+1])){
            mi++,ma++;
        }
        else{
            if(ci[b[i]]>1){ma++;}
        }
    }
    printf("%d %d\n",mi,ma);
    return 0;
}
/*
20 50
2 3
18 10
11 6
11 1
18 17
18 7
15 20
6 11
11 2
8 2
14 2
20 1
1 19
17 2
5 17
15 17
19 12
16 9
12 4
19 2
2 19
14 3
6 5
20 19
2 16
1 12
2 12
9 2
13 18
2 13
10 4
12 8
12 3
17 5
18 12
18 11
2 17
6 20
19 20
7 9
3 2
19 15
10 20
13 12
4 3
18 15
13 9
2 11
19 14
16 11
8
18 10 4 3 2 19 12 8
*/

 

posted @ 2020-03-02 15:34  ouluy  阅读(189)  评论(0编辑  收藏  举报