Shortcut(搜索 需要考虑重边)

原题: http://acm.zjnu.edu.cn/CLanguage/showproblem?problem_id=2244

题意:

n个点,每个点上有ci头牛,m条无向边,总时间定义为所有牛会走到点1的总时间。现在从点1连一条t的边到其他点,问最多可以节省多少总时间。
每头牛会走原来的最优路径,如果有多条则走字典序最小的那条。此时遇到了新建的边才可能走这条边。

解析:

这题虽然是个水题,但是我却。。

首先dijkstra求每个点到点1的距离,做完后对点u,如果存在一条边(u,v)且dis[v]+(u,v)=dis[u],那么说明u走到v是最优路径之一。那么,在这些点取一个min就是前缀了。
这样会生成一棵树,搜一遍后得出每个点会有多少牛经过,算一下即可。

我没有考虑到重边的情况,就是搜多少牛经过的时候重边就算了多次,这里加个vis即可。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for( int i=a;i<=b;i++)
#define LL long long
int read(){ int ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
LL read_LL(){ LL ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10ll+(LL)(ch-'0'),ch=getchar();
if(last=='-')ans=-ans; return ans;
}
#define pill pair<int,int>
const int maxn=2e4+4,maxm=2e5+5;

int n,m;
LL t;
struct node{
    node(){}
    node(int id,LL val):id(id),val(val){}
    int id;LL val;
    bool operator<(const node &r)const{
        return val>r.val;
    }
};
int pre[maxn],vis[maxn];
LL dis[maxn];
int head[maxn],to[maxm],nex[maxm],now;
LL val[maxm];
void add(int a,int b,LL v){
    nex[++now]=head[a];head[a]=now;to[now]=b;val[now]=v;
}
priority_queue<node>Q;
void dij(){
    for(int i=0;i<=n;i++)dis[i]=1e18;
    dis[1]=0;
    Q.push(node(1,0));
    while(!Q.empty()){
        int idx=Q.top().id;Q.pop();
        if(vis[idx])continue;
        vis[idx]=1;
        for(int i=head[idx];i;i=nex[i]){
            int v=to[i];
            if(vis[v])continue;
            if(dis[idx]+val[i]<dis[v]){
                dis[v]=dis[idx]+val[i];
                Q.push(node(v,dis[v]));
            }
        }
    }
}

LL num[maxn];
LL siz[maxn];
LL ans;

LL dfs(int p){
    vis[p]=1;
    siz[p]=num[p];
    for(int i=head[p];i;i=nex[i]){
        int v=to[i];
        if(pre[v]==p){
            if(!vis[v])
            siz[p]+=dfs(v);
        }
    }
    return siz[p];
}

int main(){
    n=read(),m=read(),t=read_LL();
    rep(i,1,n)num[i]=read_LL();
    rep(i,1,m){
        int a=read(),b=read();LL v=read_LL();
        add(a,b,v);
        add(b,a,v);
    }
    dij();
    memset(pre,0x3f,sizeof(pre));
    for(int i=1;i<=n;i++){
        for(int j=head[i];j;j=nex[j]){
            int v=to[j];
            if(dis[v]==dis[i]+val[j]&&i<pre[v])pre[v]=i;
        }
    }
    memset(vis,0,sizeof(vis));
    dfs(1);
    rep(i,1,n){
        if(t<dis[i]){
            ans=max(ans,(dis[i]-t)*siz[i]);
        }
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/88114463