bzoj1179: [Apio2009]Atm 【缩点+spfa最长路】

题目传送门

Description

Siruseri 城中的道路都是单向的。不同的道路由路口连接。按照法律的规定, 在每个路口都设立了一个 Siruser
i 银行的 ATM 取款机。令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。Bandit
ji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫。他将从市中心 出发,沿着单向道路行驶,抢劫所有他
途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利。使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的
现金数额。他希 望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可 以经过同一路口
或道路任意多次。但只要他抢劫过某个 ATM 机后,该 ATM 机 里面就不会再有钱了。 例如,假设该城中有 6 个
路口,道路的连接情况如下图所示:
市中心在路口 1,由一个入口符号→来标识,那些有酒吧的路口用双圈来表示。每个 ATM 机中可取的钱数标在了
路口的上方。在这个例子中,Banditji 能抢 劫的现金总数为 47,实施的抢劫路线是:1-2-4-1-2-3-5。
输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。
 

Sol

感觉这题思路还是很明了的...先进行一遍tarjan求出图中所有的强连通分量,将他们缩点,然后在这个DAG中跑一遍spfa求最长路。

坑点:好像不能用dijkstra+heap求最长路&&主程序中调用tarjan不能仅一次。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<stack>
  4 #include<queue>
  5 #include<cstring>
  6 #define maxn 500090
  7 
  8 using namespace std;
  9 typedef long long ll;
 10 
 11 int n,m,tot,sp,P,dfs_clock,scc_cnt;
 12 int head[maxn],Head[maxn],val[maxn],dfn[maxn],low[maxn],scc[maxn],pub[maxn];
 13 bool vis[maxn];
 14 ll ans,scc_val[maxn],dis[maxn];
 15 struct node{
 16     int to,next;
 17 }edge[maxn],Edge[maxn];
 18 stack<int>st;
 19 
 20 void add(int x,int y)
 21 {
 22     edge[++tot].to=y;
 23     edge[tot].next=head[x];
 24     head[x]=tot;
 25 }
 26 
 27 void ADD(int x,int y)
 28 {
 29     Edge[++tot].to=y;
 30     Edge[tot].next=Head[x];
 31     Head[x]=tot;
 32 }
 33 
 34 void tarjan(int u)
 35 {
 36     dfn[u]=low[u]=++dfs_clock;
 37     st.push(u);
 38     for(int i=head[u];i;i=edge[i].next)
 39     {
 40         int v=edge[i].to;
 41         if(!dfn[v])
 42         {
 43             tarjan(v);
 44             low[u]=min(low[u],low[v]);
 45         }
 46         else if(!scc[v]) low[u]=min(low[u],dfn[v]);
 47     }
 48     if(low[u]==dfn[u])
 49     {
 50         scc_cnt++;
 51         while(1)
 52         {
 53             int x=st.top();st.pop();
 54             scc[x]=scc_cnt;
 55             scc_val[scc_cnt]+=val[x];
 56             if(x==u) break;
 57         }
 58     }
 59 }
 60 
 61 void dijkstra(int s)
 62 {
 63     priority_queue<pair<ll,int> >q;
 64     for(int i=1;i<=scc_cnt;i++) dis[i]=-1;
 65     q.push(make_pair(0,s));dis[s]=scc_val[s];
 66     while(!q.empty())
 67     {
 68         int u=q.top().second;q.pop();
 69         if(vis[u]) continue;
 70         vis[u]=1;
 71         for(int i=Head[u];i;i=Edge[i].next)
 72         {
 73             int v=Edge[i].to;
 74             if(dis[v]<dis[u]+scc_val[v])
 75             {
 76                 dis[v]=dis[u]+scc_val[v];
 77                 q.push(make_pair(dis[v],v));
 78             }
 79         }
 80     }
 81 }
 82 
 83 int main()
 84 {
 85     scanf("%d%d",&n,&m);
 86     for(int i=1;i<=m;i++)
 87     {
 88         int x=0,y=0;
 89         scanf("%d%d",&x,&y);
 90         add(x,y);
 91     }
 92     for(int i=1;i<=n;i++) scanf("%d",&val[i]);
 93     for(int i=1;i<=n;i++)
 94         if(!dfn[i]) tarjan(i);
 95     tot=0;
 96     for(int x=1;x<=n;x++)
 97         for(int i=head[x];i;i=edge[i].next)
 98         {
 99             int y=edge[i].to;
100             if(scc[x]!=scc[y])
101                 ADD(scc[x],scc[y]);
102         }
103     scanf("%d%d",&sp,&P);
104     for(int i=1;i<=P;i++) scanf("%d",&pub[i]);
105     dijkstra(scc[sp]);
106     for(int i=1;i<=P;i++)
107         ans=max(ans,dis[scc[pub[i]]]);
108     printf("%lld\n",ans);
109     return 0;
110 }

 

posted @ 2018-10-25 19:05  cellur925&Chemist  阅读(121)  评论(0编辑  收藏  举报