刷题向》图论》BZOJ1179 关于tarjan和SPFA的15秒(normal)

  这道题可以考察图论的掌握程度(算半道水题)

  题目如下

  

输入

第一行包含两个整数N、M。N表示路口的个数,M表示道路条数。接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号。接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数。接下来一行包含两个整数S、P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。接下来的一行中有P个整数,表示P个有酒吧的路口的编号
输出
输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。
样例输入
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
样例输出
47
提示
50%的输入保证N, M<=3000。所有的输入保证N, M<=500000。每个ATM机中可取的钱数为一个非负整数且不超过4000。输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。
题解
这道题考到了spfa和tarjan唯一需要考虑的地方是,当你tarjan一遍之后,你需要做缩点,那么缩点之后你要做的事是重建整张图,把同一强连通分量里的点缩到同一点,再次建边,然后就是裸SPFA的事情了(缩点的过程用并查集考虑)
下面贴出代码
  1 #include<cstdio>
  2 #include<cstring>
  3 struct shit{
  4     int aim;
  5     int next;
  6     int get;
  7     bool use;
  8 }e[520000];
  9 int max(int x,int y)
 10 {
 11     return x>y?x:y;
 12 }
 13 int min(int x,int y)
 14 {
 15     return x<y?x:y;
 16 }
 17 int point,head[520000],n,m,ass,cnt,stack[520000],low[520000],time[520000],a,b,T;
 18 int father[520000],quq[520000],val[520000],d[520000],star,ans;
 19 bool f[520000];
 20 void fuck(int x,int y)
 21 {
 22     e[++point].aim=y;
 23     e[point].get=x;
 24     e[point].next=head[x];
 25     head[x]=point;
 26 }
 27 void rebuild()
 28 {
 29     memset(head,0,sizeof(head));
 30     point=0;
 31     for(int i=1;i<=m;i++)
 32         if(father[e[i].get]==father[e[i].aim]);
 33         else fuck(father[e[i].get],father[e[i].aim]);
 34 }
 35 void tarjan(int sb)
 36 {
 37     low[sb]=time[sb]=++T;
 38     f[sb]=true;
 39     stack[++ass]=sb;
 40     for(int k=head[sb];k!=0;k=e[k].next)
 41     {
 42         if(!time[e[k].aim])
 43         {
 44             tarjan(e[k].aim);
 45             low[sb]=min(low[sb],low[e[k].aim]);
 46         }
 47         else if(f[e[k].aim])low[sb]=min(low[sb],time[e[k].aim]);
 48     }
 49     if(time[sb]==low[sb])
 50     {
 51         f[sb]=false;
 52         while(stack[ass]!=sb)
 53         {
 54             val[sb]+=val[stack[ass]];
 55             f[stack[ass]]=false;
 56             father[stack[ass--]]=sb;
 57         }
 58         ass--;
 59     }
 60 }
 61 void SPFA(int num)
 62 {
 63     memset(f,0,sizeof(f));
 64     star=0,ass=1;
 65     quq[++star]=num,f[num]=true,d[num]=val[num];
 66     while(star<=ass)
 67     {
 68         int u=quq[star++];
 69         for(int k=head[u];k!=0;k=e[k].next)
 70         {
 71             int v=e[k].aim;
 72             if(d[u]+val[v]>d[v])
 73             {
 74                 d[v]=d[u]+val[v];
 75                 if(f[v])continue;
 76                     quq[++ass]=v;
 77                     f[v]=true;
 78             }
 79         }
 80         f[u]=false;
 81     }
 82     return ;
 83 }
 84 int main()
 85 {
 86     scanf("%d%d",&n,&m);
 87     for(int i=1;i<=m;i++)
 88     {
 89         scanf("%d%d",&a,&b);
 90         fuck(a,b); 
 91     }
 92     for(int i=1;i<=n;i++)
 93     {
 94         father[i]=i;
 95         scanf("%d",&val[i]);
 96     }
 97     for(int i=1;i<=n;i++)if(!time[i])tarjan(i);
 98     rebuild();
 99     scanf("%d%d",&a,&b);
100     SPFA(father[a]);
101     for(int i=1;i<=b;i++)
102     {
103         scanf("%d",&a);
104         ans=max(ans,d[father[a]]);
105     }
106     printf("%d",ans);
107     return 0;
108 }
View Code

 

posted @ 2016-09-13 13:09  PencilWang  阅读(229)  评论(0编辑  收藏  举报