codeforces 1307 D 最短路bz+贪心

别忘了无向图边开2e5*2

题意:给一个无向图,有n个点和m个边,其中包含k个特殊的点。现在让任意两个特殊的点中间连线,求1到n的最大的最短路是多少。

思路:定义两个数组d1,d2分别储存从1和从n到各各点储存的最短路长度。

  1.如果连接的两个点之间连线不影响结果ans,则ans为d1[n]

  2.如果这两个点影响,设这两个点分别为a,b。ans = min(d1[a]+d2[b]+1,d2[a]+d1[b]+1)

则问题转化为

给两个长度为n的数组a,b。
如何在O(n)的复杂度求出i和j(i!=j)
使得min(ai+bj,aj+bi)最大。

假若让ai+bj

可以领两个数组根据ai-bi进行排序,遍历1-n,当遍历到posj的时候,最优解posi为【1-posj-1】的最大a的下标,随便维护一下即可。

#include 
#include 
#include 
#include 
#include <string>
#include 
#include 
#include 
#include 
#include 
#include <set>
#include  
// #include 
#define fastio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define sp ' '
#define endl '\n'
#define inf  0x3f3f3f3f
#define FOR(i,a,b) for( int i = a;i <= b;++i)
#define bug cout<<"--------------"<#define P pair
#define fi first
#define se second
#define pb(x) push_back(x)
#define ppb() pop_back()
#define mp(a,b) make_pair(a,b)
#define ms(v,x) memset(v,x,sizeof(v))
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repd(i,a,b) for(int i=a;i>=b;i--)
#define sca3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define sca2(a,b) scanf("%d %d",&(a),&(b))
#define sca(a) scanf("%d",&(a));
#define sca3ll(a,b,c) scanf("%lld %lld %lld",&(a),&(b),&(c))
#define sca2ll(a,b) scanf("%lld %lld",&(a),&(b))
#define scall(a) scanf("%lld",&(a));


using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll powmod(ll a, ll b, ll mod){ll sum = 1;while (b) {if (b & 1) {sum = (sum * a) % mod;b--;}b /= 2;a = a * a % mod;}return sum;}

const double Pi = acos(-1.0);
const double epsilon = Pi/180.0;
const int maxn = 4e5+10;
int n,m,k;
int ver[maxn],head[maxn],nextt[maxn],vis[maxn],edge[maxn*2];
priority_queueint,int>  >que;
priority_queueint,int>  >que2;
int tot;
int d1[maxn],d2[maxn];
int spe[maxn];
void add(int x,int y,int z) //邻接矩阵,x是这条边的起点,y是终点,z是长度
{
    ver[++tot]=y,edge[tot]=z;
    nextt[tot]=head[x],head[x]=tot;
}

void dijkstra1(int origin)  //求origin到各个点的最短长度
{   
    memset(d1,9999999,sizeof(d1));
    memset(vis,0,sizeof(vis));
    d1[origin]=0;
    que.push(make_pair(0,origin));
    while(que.size())
    {
        int x=que.top().second;
        que.pop();
        if(vis[x]==1) continue;
        vis[x]=1;

        for(int i=head[x];i;i=nextt[i])
        {
            int y=ver[i];
            int z=edge[i];
            if(d1[y]>d1[x]+z)
            {
                d1[y]=d1[x]+z;
                que.push(make_pair(-d1[y],y));
            }
        }
    }
}
void dijkstra2(int origin)  //求origin到各个点的最短长度
{   
    memset(d2,9999999,sizeof(d2));
    memset(vis,0,sizeof(vis));
    d2[origin]=0;
    que.push(make_pair(0,origin));
    while(que.size())
    {
        int x=que.top().second;
        que.pop();
        if(vis[x]==1) continue;
        vis[x]=1;

        for(int i=head[x];i;i=nextt[i])
        {
            int y=ver[i];
            int z=edge[i];
            if(d2[y]>d2[x]+z)
            {
                d2[y]=d2[x]+z;
                que.push(make_pair(-d2[y],y));
            }
        }
    }
}

struct node
{
    int id,x;
}p[maxn];
bool cmp(node a,node b)
{
    return a.x<b.x;
}
int a[maxn];
int main()
{
    //freopen("input.txt", "r", stdin);
    cin>>n>>m>>k;
    rep(i,1,k){
        cin>>a[i];
    }
    rep(i,1,m){
        int x,y;
        cin>>x>>y;
        add(x,y,1);
        add(y,x,1);
    }
    dijkstra1(1);
    dijkstra2(n);
      rep(i,1,k)
    {
        p[i].id=a[i];
        p[i].x=d1[a[i]]-d2[a[i]];
    }
    sort(p+1,p+1+k,cmp);
    int maxx = 0,ans = 0;
    for (int i=1;i<=k;i++)
    {
        int num=p[i].id;
       // cout<
        if (i==1)maxx=d1[num];
        else
        {
            //cout<
            ans=max(ans,maxx+d2[num]+1);
            maxx=max(maxx,d1[num]);
        }
       // cout<
    }
    cout<<min(ans,d1[n]);


}

 

你可能感兴趣的:(codeforces 1307 D 最短路bz+贪心)