解题报告:CF1307D Cow and Fields(最短路、最优解不等式化简)

CF1307D Cow and Fields
解题报告:CF1307D Cow and Fields(最短路、最优解不等式化简)_第1张图片

整张无向图的边权为1。

首先求出 1 , n 1,n 1,n 两个点的单源最短路径。这 k k k 个特殊点中,我们令第 a a a 个特殊点到 1 1 1 的距离为 x a x_a xa,到 n n n 的距离为 y a y_a ya。设答案是连接 a , b a,b a,b 两点。

我们的目的就是最大化 m i n ( x a + y b + 1 , y a + x b + 1 ) min(x_{a} + y_{b} + 1,y_{a} + x_{b} +1) minxa+yb+1ya+xb+1)
为了不失一般性,我们设
x a + y b ≤ y a + x b 。 x_{a} +y_{b}≤y_{a}+ x_{b}。 xa+ybya+xb
我们可以化简成(分离变量,因为我们必须是同一个 a a a 才能排序)
x a − y a ≤ x b − y b x_{a}-y_{a}≤x_{b}-y_{b} xayaxbyb
我们按照 x a − y a x_{a}-y_{a} xaya来排序,这样排完序之后的 a a a b b b就 拥有了一个性质: a < b aa<b a a a 一定在 b b b 的前面)
因此我们倒序处理Max[i]数组,表示的是 i i i 右边(包括自己)最大的 y i y_i yi

然后我们正序求当前结点 a a a x a + y b + 1 x_a + y_b + 1 xa+yb+1(只能和右边 b b b 的匹配) 的最大值即可。

#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;

const int N = 510007, M = 510007, INF = 0x3f3f3f3f;
int t;
int n,m,k;
int dist[N];
bool vis[N];
int ver[M],nex[M],edge[M],head[N],tot;
int cnt;
int a[N],b[N];
int maxx,minn;
map<int,int>mp;

int Max[N];
int dis1[N],disn[N];


void add(int x,int y,int z){
    ver[tot] = y;
    nex[tot] = head[x];
    edge[tot] = z;
    head[x] = tot ++ ;
}

struct node{
    int dis1,disn;
    bool operator<(const node &t)const{
        return dis1 - disn < t.dis1 - t.disn;
    }
}pos[N];

priority_queue<PII,vector<PII>,greater<PII> >q;

void Dijkstra(int S){
    memset(dist,0x3f,sizeof dist);
    memset(vis,0,sizeof vis);
    dist[S] = 0;
    q.push({dist[S],S});
    while(q.size()){
        int x = q.top().second;
        q.pop();
        if(vis[x])continue;
        vis[x] = true;
        for(int i = head[x];~i;i = nex[i]){
            int y = ver[i],z = edge[i];
            if(dist[y] > dist[x] + z){
                dist[y] = dist[x] + z;
                q.push({dist[y],y});
            }
        }
    }
}

int main(){
    memset(head,-1,sizeof head);
    scanf("%d%d%d",&n,&m,&k);

    for(int i = 1;i <= k;++i)
        scanf("%d",&a[i]);
    for(int i = 1;i <= m;++i){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y,1);
        add(y,x,1);
    }

    Dijkstra(1);
    for(int i = 1;i <= n;++i)
        dis1[i] = dist[i];
    Dijkstra(n);
    for(int i = 1;i <= n;++i)
        disn[i] = dist[i];

    for(int i = 1;i <= k;++i)
    pos[i] = {dis1[a[i]],disn[a[i]]};
    sort(pos + 1,pos + 1 + k);

    int ans = 0;
    for(int i = k;i;--i)
        Max[i] = max(Max[i + 1],pos[i].disn);
    for(int i = 1;i < k;++i)
        ans = max(ans,pos[i].dis1 + Max[i + 1] + 1);
    ans = min(ans,dis1[n]);
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(#,最短路算法)