经典排序策略——cf1307D

惨痛教训,这种排序在01背包里也有类似的题目,为啥比赛会想错呢

https://blog.csdn.net/the_love_story/article/details/52179575

/*
每个点i:有两个特征值a[i],b[i] 
求两个点i,j,使min(a[i]+b[j],a[j]+b[i])最大
经典的排序问题:就是按 a[i]-b[i]进行排序,这样排序出来后可以确定:
    对于所有i<j 都有a[i]-b[i]<a[j]-b[j] => a[i]+b[j]<a[j]+b[i]
    => 对于所有i<j 其 min(a[i]+b[j],a[j]+b[i]) 的结果都是 a[i]+b[j]
    => 对于每个a[i],我们去找max(b[j]),j>i即可 
*/
#include<bits/stdc++.h>
using namespace std;
#define N 200005

vector<int>G[N];
int n,m,k;
int aa[N],a[N],b[N],f[N];
void bfs(int s,int *dis){
    queue<int>q;q.push(s);
    dis[s]=0;
    while(q.size()){
        int u=q.front();q.pop();
        for(auto v:G[u]){
            if(dis[v] || v==s)continue;
            dis[v]=dis[u]+1;
            q.push(v);
        }
    }
}
struct Node{
    int a,b,id;
}p[N];
int cmp(Node a,Node b){return a.a-a.b<b.a-b.b;}
int suf[N];

int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=k;i++)cin>>aa[i],f[aa[i]]=1;
    int flag=0;
    for(int i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        G[u].push_back(v);
        G[v].push_back(u);
        if(f[u] && f[v])flag=1;
    }
    bfs(1,a);
    bfs(n,b);
    
    if(flag){cout<<a[n]<<'\n';return 0;}
    
    int tot=0;
    for(int i=1;i<=n;i++)if(f[i]){
        ++tot;
        p[tot].a=a[i];
        p[tot].b=b[i];
        p[tot].id=i;
    }
    sort(p+1,p+1+k,cmp);
    
    suf[k]=p[k].b;
    for(int i=k-1;i>=1;i--)
        suf[i]=max(suf[i+1],p[i].b);
    int Max=0;
    for(int i=1;i<=k-1;i++)
        Max=max(Max,suf[i+1]+p[i].a);
    cout<<min(Max+1,a[n])<<'\n';
} 

 

posted on 2020-02-18 13:20  zsben  阅读(198)  评论(0编辑  收藏  举报

导航