【bzoj1179】 Apio2009—Atm

www.lydsy.com/JudgeOnline/problem.php?id=1179 (题目链接)

题意:给出一张有向图,每个节点有点权。标记一些点,找出一条路径,可以重复经过一条边,使得总点权和最大。重复经过一个点不能重复算点权。

Solution 
  今日考试题,Dijkstra不幸Gi烂。 
  WARNING:Dijkstra处理最长路时会出现一些不好的情况,所以千万不要用!! 
  既然可以重复经过一些边,那么一旦经过了某个环,我们一定可以把环上所有的点跑遍,所以做法就很显然了。先Tarjan缩点,所以整个图就变成有向无环图,跑DP或者SPFA最长路即可。

代码:

// bzoj1179
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=500010;
struct data {
    int num,x;
    friend bool operator < (const data &x,const data &y) {
        return x.x<y.x;
    }
};
struct edge {int to,next;}e[maxn<<1];
struct E {int u,v;}ee[maxn];
int dis[maxn],head[maxn],dfn[maxn],low[maxn],st[maxn],vis[maxn],pos[maxn],a[maxn],w[maxn],ll[maxn];
int n,m,top,sum,cnt,S,ind,p;

void link(int u,int v) {
    e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;
}
void Tarjan(int x) {
    dfn[x]=low[x]=++ind;
    vis[x]=1;
    st[++top]=x;
    for (int i=head[x];i;i=e[i].next) {
        if (!vis[e[i].to]) {
            Tarjan(e[i].to);
            low[x]=min(low[x],low[e[i].to]);
        }
        else if (!pos[e[i].to])
            low[x]=min(low[x],dfn[e[i].to]);
    }
    if (dfn[x]==low[x]) {
        sum++;
        int j;
        do {
            j=st[top--];
            pos[j]=sum;w[sum]+=a[j];
        }while (st[top+1]!=x);
    }
}
void Dijkstra() {
    priority_queue<data> q;
    for (int i=1;i<=sum;i++) dis[i]=-inf;
    data y,x=(data){S,w[S]};
    q.push(x);dis[S]=w[S];
    while (q.size()) {
        x=q.top();q.pop();
        if (vis[x.num]) continue;
        vis[x.num]=1;
        for (int i=head[x.num];i;i=e[i].next)
            if (dis[e[i].to]<dis[x.num]+w[e[i].to]) {
                dis[e[i].to]=y.x=dis[x.num]+w[e[i].to];
                y.num=e[i].to;
                q.push(y);
            }
    }
}
void SPFA() {
    queue<int> q;
    for (int i=1;i<=sum;i++) dis[i]=-inf;
    q.push(S);dis[S]=w[S];
    while (q.size()) {
        int x=q.front();q.pop();
        vis[x]=0;
        for (int i=head[x];i;i=e[i].next)
            if (dis[e[i].to]<dis[x]+w[e[i].to]) {
                dis[e[i].to]=dis[x]+w[e[i].to];
                if (!vis[e[i].to]) q.push(e[i].to);
            }
    }
}
int main() {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++) {
        scanf("%d%d",&ee[i].u,&ee[i].v);
        link(ee[i].u,ee[i].v);
    }
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    scanf("%d%d",&S,&p);
    Tarjan(S);S=pos[S];
    for (int x,i=1;i<=p;i++) {
        scanf("%d",&x);
        ll[pos[x]]=1;
    }
    for (int i=1;i<=n;i++) vis[i]=head[i]=0;
    for (int i=1;i<=m;i++)
        if (pos[ee[i].u]!=pos[ee[i].v]) link(pos[ee[i].u],pos[ee[i].v]);
    //Dijkstra();   万万不可
    SPFA();
    int ans=0;
    for (int i=1;i<=sum;i++) if (ll[i]) ans=max(ans,dis[i]);
    printf("%d",ans);
    return 0;
}

  

时间: 2024-11-24 12:04:58

【bzoj1179】 Apio2009—Atm的相关文章

【bzoj1179】[Apio2009]抢掠计划atm 强连通分量缩点+spfa

Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口的编号 Output 输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数. Sample

【BZOJ-1179】Atm Tarjan + SPFA

1179: [Apio2009]Atm Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 2407  Solved: 993[Submit][Status][Discuss] Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来

【BZOJ 1179】[Apio2009]Atm

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] tarjan强连通缩点一下. 然后把缩点之后,每个点的钱的数累加起来. 然后从S出发 开始一边做bfs一遍做dp. 最后输出有酒吧的点的dp值中的最大值. [代码] /* n个点,m条有向边. 把有向图G的环进行缩点; 缩完之后的图存在vector <int> g[N]里面; n变为缩完点之后的图的节点的个数了. */ #include <bits/stdc++.h> using namespace std; #d

【BZOJ1179】【Apio2009】Atm 强连通分量缩点+拓扑DP/拓扑最长路 kosaraju+tarjan+dfs转非递归三种代码

题解: 首先第一个阶段, 可以写kosaraju.也可以写tarjan. 这两种还都分递归和dfs转非递归. ----------------------------------四种方案. 第二个阶段,可以写拓扑DP 也可以写最长路 ----------------------------------乘上之前的,,八种方案. 本文写了kosaraju递归版,tarjan递归版,kosaraju非递归版. --只怪学校oj系统栈太小..都是逼得啊. 代码1(tarjan): #include <c

【BZOJ1179】Atm

tarjan缩点 之后跑一边spfa即可 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 const int N=500010,novis=-1,over=1,nowvis=0; 5 int head1[N],head2[N],value[N],n,m,size,ans; 6 int low[N],dfn[N],flag[N],que[N],sum[N],color[N], 7 cnt,sig,top;

【p3627】[APIO2009] 抢掠计划

Description Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧. Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫.他将从市中心 出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利. 使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金

【bzoj1178】 Apio2009—CONVENTION会议中心

http://www.lydsy.com/JudgeOnline/problem.php?id=1178 (题目链接) 题意 给出n个区间,问在区间两两不相交的情况下最多能选出多少区间,并输出字典序最小的方案. Solution 考试看错题,,还有60分.. 很巧妙的一道题. 代码 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cs

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

[bzoj] 1179: [Apio2009]Atm Description Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧.Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫.他将从市中心 出发,沿着单向道路行驶,抢劫所有他 途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利.使用高超

【Tarjan】+【SPFA】【APIO2009】Atm

一.算法介绍 tarjan——求解有向图强连通分量.这个算法在本人的一篇blog中有介绍,这里就不赘述了.贴上介绍tarjan的的blog链接:http://www.cnblogs.com/Maki-Nishikino/p/5866191.html 那么接下来说说SPFA: SPFA全称Shortest Path Faster Algorithm,用于求解单源最短路.既然名字中有“Faster”,那它就一定有过人之处,事实上它也的确比Dijkstra和Bellman-Ford更高效. 它的思路大