#图# #SPFA# #Tarjan# ----- BZOJ1179

SPFA算法

  1. SPFA(Shortest Path Faster Algorithm)(队列优化)算法是求单源最短路径的一种算法。
  2. 判负环(在差分约束系统中会得以体现)。如果某个点进入队列的次数超过N次则存在负环(SPFA无法处理带负环的图)

tarjan算法

Tarjan算法是用来求有向图的强连通分量的。

Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。
定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。
当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。
 
BZOJ 1179

Input

第一行包含两个整数N、M。N表示路口的个数,M表示道路条数。接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号。接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数。接下来一行包含两个整数S、P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。接下来的一行中有P个整数,表示P个有酒吧的路口的编号

Output

输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。

Sample Input

6 7
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10
12
8
16
1 5
1 4
4
3
5
6

Sample Output

47

HINT

50%的输入保证N, M<=3000。所有的输入保证N, M<=500000。每个ATM机中可取的钱数为一个非负整数且不超过4000。输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。

 

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 using namespace std;
  5 
  6 int n,m,st,p;
  7 int ans;
  8 int money[500010],moneys[500010];
  9 int q[500010],b,e,d[500010];//spfa
 10 int stack[500010],dfn[500010],low[500010],index,top;//tarjan
 11 bool vis[500010];
 12 int color[500010],num;
 13 
 14 struct node{
 15     int u;
 16     int v;
 17     int next;
 18 }s[500010],map[500010];
 19 int head[500010],rehead[500010],cnt;
 20 
 21 void add(int x,int y){
 22     s[++cnt].u=x;
 23     s[cnt].v=y;
 24     s[cnt].next=head[x];
 25     head[x]=cnt;
 26 }
 27 
 28 void tarjan(int x){
 29     dfn[x]=++index;
 30     low[x]=index;
 31     stack[++top]=x;
 32     vis[x]=true;
 33 
 34     for(int i=head[x];i!=0;i=s[i].next){
 35         if(!dfn[s[i].v]){
 36             tarjan(s[i].v);
 37             low[x]=min(low[x],low[s[i].v]);
 38         }
 39         else if(vis[s[i].v]==true)low[x]=min(low[x],dfn[s[i].v]);
 40     }
 41 
 42     if(dfn[x]==low[x]){
 43         vis[x]=false;
 44         color[x]=++num;//计算个数
 45         while(stack[top]!=x){
 46             color[stack[top]]=num;
 47             vis[stack[top--]]=false;
 48         }
 49         top--;
 50     }
 51 }
 52 
 53 void rebuild(){//缩点
 54     cnt=0;
 55     for(int i=1;i<=n;i++){
 56         for(int j=head[i];j!=0;j=s[j].next){
 57             if(color[i]!=color[s[j].v]){
 58                 map[++cnt].u=color[i];
 59                 map[cnt].v=color[s[j].v];
 60                 map[cnt].next=rehead[color[i]];
 61                 rehead[color[i]]=cnt;
 62             }
 63         }
 64     }
 65 }
 66 
 67 void spfa(int x){
 68     memset(vis,false,sizeof(vis));
 69     q[++b]=x;
 70     e++;
 71     vis[x]=true;
 72     d[x]=moneys[x];
 73     while(b<=e){
 74         int y=q[b++];
 75         for(int i=rehead[y];i!=0;i=map[i].next){
 76             if(d[map[i].v]<d[y]+moneys[map[i].v]){
 77                d[map[i].v]=d[y]+moneys[map[i].v];
 78                if(!vis[map[i].v]){
 79                   q[++e]=map[i].v;
 80                   vis[map[i].v]=true;
 81                 }
 82             }
 83         }
 84         vis[q[b]]=false;
 85     }
 86 }
 87 
 88 int main(){
 89 
 90     scanf("%d%d",&n,&m);
 91     for(int i=1;i<=m;i++){
 92         int a,b;
 93         scanf("%d%d",&a,&b);
 94         add(a,b);
 95     }
 96 
 97     for(int i=1;i<=n;i++)
 98         if(!dfn[i])tarjan(i);
 99 
100     rebuild();//重建图
101 
102     for(int i=1;i<=n;i++){
103        scanf("%d",&money[i]);
104        moneys[color[i]]+=money[i];
105     }
106 
107     scanf("%d%d",&st,&p);
108 
109     spfa(color[st]);
110 
111     for(int i=1;i<=p;i++){
112         int a;
113         scanf("%d",&a);
114         ans=max(ans,d[color[a]]);
115     }
116     printf("%d",ans);
117 
118     return 0;
119 }

 

posted @ 2016-11-02 16:33  WJ-Ting  阅读(302)  评论(0编辑  收藏  举报