首页 > 学院 > 开发设计 > 正文

FZU 2169 shadow【最短路+思维】

2019-11-08 20:14:50
字体:
来源:转载
供稿:网友

 PRoblem 2169 shadow

Accept: 373    Submit: 1462Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

YL是shadow国的国王,shadow国有N个城市。为了节省开支,shadow国只有N-1条道路,这N-1条道路使得N个城市连通。某一年,shadow国发生了叛乱,叛军占领了多个城市,王都岌岌可危。王都为编号为1的城市,除了王都外有K个城市有YL的军队。现在这K支军队要向王都进军,并且消灭沿途经过的城市中的叛军。现给出N个城市的道路情况以及城市的叛军数量,问总共需要消灭多少叛军?

 Input

第一行输入两个整数N,K,接下来输入N(1<=N<=100000)个整数Ai(0<=Ai<=10000),表示第i个城市的叛军数量。接下来输入K个大于等于1且小于等于N的整数,表示有军队的城市的编号。数据保证王都以及有军队的城市没有叛军。接下来输入N-1行,每行两个整数u、v,表示连接u和v的一条道路。每支军队只能沿着道路走,并且是其所在城市与王都之间的最短路线走。

 Output

输出一行一个整数表示消灭的叛军数量。

 Sample Input

4 20 3 0 03 41 22 32 4

 Sample Output

3

思路:

1、首先知道这个图是一个无向图,那么对应如果求出来了从u到v的最短路,那么也就等价于求出了从v到u的最短路。

那么很容易想到,对应需要求出K个军队到到1号节点的最短路径都要走哪些点,其实就是要求一个单源最短路,求出从节点1到其他各个节点的最短路径都要走哪些点。

2、那么过程维护一个数组pre【i】=x,表示以1作为源点的从1到i的最短路上,到达i之前到达的点是x。那么每一次松弛的同时,要对pre【v】进行更新。

那么我们只要一遍循环就能求出从某一个点到节点1的路径上都经过了哪些点。

但是这里需要进行K次循环,显然如果N比较大而且K比较大的时候会TLE.

那么我们考虑对这个图继续进行分析:根据题干所述,这N个点是用N-1条边来连通的,那么显然这个图还是一棵树。

那么这里同时保证,从一个点u,到点1的最短路(或者说路径),只有一条。

那么其实在循环找前驱的过程中,如果有到达同一个点的情况(比如x,y两个节点要到1号节点取,都共同经过了4号节点的话,那么其实在4号节点之后的路径 ,这两个点的路径是重复并且相同的),那么我们过程维护一个vis【i】数组,表示之前的路径中,是否经过了i号节点,如果已经经过了,那么肯定存在两个节点共同经过一段重复路径,那么之后的循环部分就可以break掉了。

3、注意处理好细节。另外,用vector存图莫名TLE.改用邻接表就没问题.....

Ac代码:

#include<stdio.h>#include<string.h>#include<vector>#include<queue>using namespace std;struct node{    int from;    int to;    int w;    int next;}e[260070];int head[160007];int cont;void add(int from,int to,int w){    e[cont].to=to;    e[cont].w=w;    e[cont].next=head[from];    head[from]=cont++;}int dis[150060];int pre[150060];int vis[150060];int a[150060];int army[150060];int n,m;void SPFA(int ss){    memset(vis,0,sizeof(vis));    memset(pre,-1,sizeof(pre));    for(int i=1;i<=n;i++)dis[i]=0x3f3f3f3f;    dis[ss]=0;    queue<int >s;    s.push(ss);    while(!s.empty())    {        int u=s.front();        //vis[u]=0;        s.pop();        for(int i=head[u];i!=-1;i=e[i].next)        {            int v=e[i].to;            if(dis[v]>dis[u]+1)            {                dis[v]=dis[u]+1;                pre[v]=u;                if(vis[v]==0)                {                    vis[v]=1;                    s.push(v);                }            }        }    }    memset(vis,0,sizeof(vis));    int output=0;    for(int i=1;i<=m;i++)    {        int now=army[i];        while(now!=-1)        {            if(vis[now]==0)            {                output+=a[now];                a[now]=0;                vis[now]=1;            }            else break;            now=pre[now];        }    }    printf("%d/n",output);}int main(){    while(~scanf("%d%d",&n,&m))    {        int cont=0;        memset(head,-1,sizeof(head));        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);        }        for(int i=1;i<=m;i++)        {            scanf("%d",&army[i]);        }        for(int i=0;i<n-1;i++)        {            int x,y;            scanf("%d%d",&x,&y);            add(x,y,1);            add(y,x,1);        }        SPFA(1);    }}


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表