P3393 逃离僵尸岛

kkk 口中的模板题,当我一直在wa的时候一直在想这题怎么会是模板题???但做完发现确实是模板题,,,

这道题,告诉了我这种只会模板的蒟蒻求最短路时,bfs在所需要的节点比较少时(距离比较短时)或许是个很好的选择。

首先,先说下自己的思路,我一开始想的是对每一个感染城市跑spfa找危险城市,最后再跑一遍对全图的spfa,然而只有28分,t两个点(6,7),wa了三个点(2,3,4);

28分代码:

#include<iostream>
#include<cstdio> 
#include<algorithm>
#include<cstring>
#include<queue> 
using namespace std;
inline int read(){
    int x = 0;int f = 1;char c = getchar();
    while(c<'0'||c>'9'){
        if(c == '-')f = -f;
        c = getchar();
    }
    while(c<='9'&&c>='0'){
        x = x*10 + c - '0';
        c = getchar();
    } 
    return x*f;
}
const int maxn = 2002000;
const int inf = 2147483647;
int cnt,p,q,n,m,k,s;
int x[maxn],y[maxn],val[maxn],vis[maxn],c[maxn],head[maxn*2];
long long dis[maxn];
struct edge{
    int from,to,v;
}e[maxn];
void add(int a,int b,int c){
    cnt++;
    e[cnt].from = head[a];
    e[cnt].to = b;
    e[cnt].v = c;
    head[a] = cnt; 
} 
void spfa(int start){
    for(int i = 1; i<=n; i++)dis[i] = inf;
    memset(vis,0,sizeof(vis));
    queue<int>que;
    que.push(start);
    dis[start] = 0;
    vis[start] = 1;
    while(!que.empty()){
        int f = que.front();que.pop();
        vis[f] = 0;
        for(int i = head[f] ; i ;i = e[i].from){
            int u = e[i].to;
            if(dis[u] > dis[f] + e[i].v){
                dis[u] = dis[f] + e[i].v;
                if(!vis[u]){
                    vis[u] = 1;
                    que.push(u);
                }
            }
        }
    } 
}
int main(){
    n = read();m = read();k = read();s = read();
    p = read();q = read();
    for(int i = 1; i<=k; i++)c[i] = read();
    for(int i = 1; i<=m; i++){
        int a,b;
        x[i] = read(); y[i] = read();
        add(x[i],y[i],1);
        add(y[i],x[i],1);
    }
    for(int i = 1; i<=n; i++)val[i] = p;
    for(int i = 1; i<=k; i++){
        spfa(c[i]);
        for(int i = 1; i<=n; i ++){
            if(dis[i] <= s)val[i] = q;
        } 
    }// for(int i = 1; i<=n; i++)cout<<dis[i]<<' '; 
    val[1] = 0;val[n] = 0;
    memset(e,0,sizeof(e));
    memset(head,0,sizeof(head));
    for(int i = 1; i<=m; i++){
        add(x[i],y[i],val[y[i]]);
        add(y[i],x[i],val[x[i]]);
    }
    //cout<<dis[n]<<' ';

    spfa(1);
    printf("%lld",dis[n]);

    return 0;
}

其实很容易就发现对于全图的spfa是很浪费的当距离超过s完全就可以停止,所以我们基于spfa的思想对所有僵尸控制的城市进行bfs对在s距离内的城市进行标记,bfs结束后,对边权进行赋值,一条边的权值为这条边所指向城市的旅店所需花费,(所以这里需要注意当指向城市为n时需要跳过),最后一遍最短路即可求出所需花费,但在这里需要注意两点!!!

1 :开long long

2:dis 最大值因为会爆int的缘故所以不能用2147483647!!!

贴代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue> 
#include<cstring>
#define inf 31147483647//因为会爆int所以所求的值会超过214748367,所以一定要比2147483647大
#define ll long long
using namespace std;
inline int read(){
    int x = 0;int f = 1;char c = getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
    while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
const int maxn = 5000000;
int cnt,n,m,k,ans,s,p,q;
queue<int>que;
struct edge{
    int from,to,v;
}e[maxn];
ll dis[maxn];
int head[maxn],vis[maxn],flag[maxn];
void add(int a,int b){
    cnt++;
    e[cnt].from = head[a];
    e[cnt].to = b;
    head[a] = cnt;
}
void spfa(){
    memset(vis,0,sizeof(vis));
    for(int i = 1; i<=n; i++)dis[i] = inf;
    que.push(1);
    dis[1] = 0;
    vis[1] = 1;
    while(!que.empty()){
        int f = que.front();que.pop();
        vis[f] = 0;
        for(int i = head[f] ; i ; i =e[i].from){
            int u = e[i].to;
            if(dis[u] > dis[f] + e[i].v){
                dis[u] = dis[f] + e[i].v;
                if(!vis[u]){
                    vis[u] = 1;
                    que.push(u);
                }
            }
        } 
    } 
}
int main(){
    n = read(); m = read(); k = read(); s = read(); p = read(); q = read();
    for(int i = 1; i<=k; i++){
        int a;
        a = read();
        flag[a]++;//标记僵尸控制的城市
        que.push(a);
    }
     for(int i = 1; i<=m; i++){
        int a,b;
        a = read();
        b = read();
        add(a,b);
        add(b,a);
     } 
     //bfs求危险城市
    while(!que.empty()){
        int f = que.front();que.pop();
        if(dis[f] == s)continue;
        for(int i = head[f] ; i ; i = e[i].from){
            if(dis[e[i].to] == 0){
            dis[e[i].to] = dis[f] + 1;
            que.push(e[i].to);  
            }
        }
    }  
   //对边权赋值
    for(int i = 1; i<=cnt; i++){
        if(e[i].to == n)continue;//终点不包括在内的原因所以跳过
        //如果是被僵尸控制的城市把边权赋值成一个极大值保证这条边不会出现在最后所求的路径里
        if(flag[e[i].to]){
            e[i].v = inf;
            continue;
        }
        //如果是危险城市赋值成q否则复制成p
        if(dis[e[i].to])e[i].v =q;
        else e[i].v = p;
    }
    spfa();
    printf("%lld",dis[n]);  
    return 0;
}

完结

posted @ 2018-11-05 08:56  Euplectella  阅读(162)  评论(0编辑  收藏  举报