【BZOJ-1179】Atm Tarjan + SPFA

1179: [Apio2009]Atm

Time Limit: 15 Sec  Memory Limit: 162 MB
Submit:
2407  Solved: 993
[Submit][Status][Discuss]

Description

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的单向的道路到达其中的至少一个酒吧。

Source

Solution

挺不错的结合,挺好实现的

首先题目中有环,很显然换上的都可以取到,但这不符合一般的最短/长路的跑法,所以考虑转化

把图中的环缩成一个点,点权为环上的值总和,对缩出来的点重构图,连边

很显然是个DAG,那么如此这样就可以直接跑了,直接上SPFA跑一遍即可,实际上BFS也可以..

最后枚举所有的酒吧,判断在哪里结束获得最大即可

PS:开始重建图的时候,是在原来的基础上建的,为什么RE成狗?迫使我新开一个重新建...

启发:

有向图出现环,很有可能需要缩成点,这个思想可以应用与最短路,或者网络流上

想题要周到,方便实现的写法,往往最适合

遇到DAG时,尝试利用一下DAG的性质,可能会有奇效

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define maxn 500010
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}
    while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();}
    return x*f;
}
int n,m,uu,S,P,ans,val[maxn]; 

struct Edgenode{int to,next,val;}edge[maxn<<1];
int head[maxn<<1],cnt=1;
void add(int u,int v)
{cnt++;edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt;}
struct Roadnode{int to,next;}road[maxn];
int last[maxn],cn=1;
void insert(int u,int v)
{cn++;road[cn].to=v;road[cn].next=last[u];last[u]=cn;}
int dfn[maxn],low[maxn],qcnt,stack[maxn],top,num[maxn],belong[maxn],tot,valu[maxn];
bool visit[maxn]; 

void Tarjan(int x)
{
    dfn[x]=low[x]=++tot;
    visit[x]=1; stack[++top]=x;
    for (int i=head[x]; i; i=edge[i].next)
        {
            if (!dfn[edge[i].to])
                {
                    Tarjan(edge[i].to);
                    if (low[edge[i].to]<low[x]) low[x]=low[edge[i].to];
                }
            else
                if(visit[edge[i].to] && dfn[edge[i].to]<low[x])
                    low[x]=dfn[edge[i].to];
        }
    if (dfn[x]==low[x])
        {
            qcnt++;
            while (x!=uu)
                uu=stack[top--],num[qcnt]++,visit[uu]=0,belong[uu]=qcnt,valu[qcnt]+=val[uu];
        }
}
void rebuild()
{
    for (int i=1; i<=n; i++)
        for (int j=head[i]; j; j=edge[j].next)
            if (belong[i]!=belong[edge[j].to])
                insert(belong[i],belong[edge[j].to]);
}
#define inf 0x7fffffff
int dis[maxn];
void spfa()
{
    queue<int>que; memset(visit,0,sizeof(visit));
//  for (int i=1; i<=qcnt; i++) dis[i]=-inf;
    visit[S]=1; dis[S]=valu[S]; que.push(S);
    while (!que.empty())
        {
            int now=que.front(); que.pop(); visit[now]=0;
            for (int i=last[now]; i; i=road[i].next)
                if (dis[road[i].to]<dis[now]+valu[road[i].to])
                    {
                        dis[road[i].to]=dis[now]+valu[road[i].to];
                        if (!visit[road[i].to])
                            visit[road[i].to]=1,que.push(road[i].to);
                    }
        }
}
bool bar[maxn];
int main()
{
    n=read(),m=read();
    for (int u,v,i=1; i<=m; i++) u=read(),v=read(),add(u,v);
    for (int i=1; i<=n; i++) val[i]=read();
    for (int i=1; i<=n; i++) if (!dfn[i]) Tarjan(i);
    S=read(); S=belong[S]; P=read();
    for (int x,i=1; i<=P; i++) x=read(),bar[x]=1;
    rebuild(); spfa();
//  for (int i=1; i<=n; i++)
//      printf("%d\n",dis[belong[i]]);
    for (int i=1; i<=n; i++)
        if (bar[i]) ans=max(ans,dis[belong[i]]);
    printf("%d\n",ans);
    return 0;
}

似乎是个不错的NOIP难度题?

时间: 2024-12-17 01:43:58

【BZOJ-1179】Atm Tarjan + SPFA的相关文章

bzoj 1179[Apio2009]Atm (tarjan+spfa)

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

BZOJ 1179: [Apio2009]Atm( tarjan + 最短路 )

对于一个强连通分量, 一定是整个走或者不走, 所以tarjan缩点然后跑dijkstra. --------------------------------------------------------------------- #include<bits/stdc++.h> #define rep(i, n) for(int i = 0; i < n; ++i) #define clr(x, c) memset(x, c, sizeof(x)) #define foreach(i,

【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

【BZOJ 2820】 YY的GCD

2820: YY的GCD Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 807  Solved: 404 [Submit][Status] Description 神犇YY虐完数论后给傻×kAc出了一题 给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对 kAc这种傻×必然不会了,于是向你来请教-- 多组输入 Input 第一行一个整数T 表述数据组数 接下来T行,每行两个正整数,表示

【BZOJ 1854】 [Scoi2010]游戏

1854: [Scoi2010]游戏 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 2609  Solved: 931 [Submit][Status] Description lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示.当他使用某种装备时,他只能使用该装备的某一个属性.并且每种装备最多只能使用一次. 游戏进行到最后,lxhgww遇到了终极boss,这个终极bos

【BZOJ 1036】【ZJOI 2008】树的统计

此题为树链剖分的裸题. 代码如下,使用常用的轻重链剖分. /************************************************************** Problem: 1036 User: Evensgn Language: C++ Result: Accepted Time:2468 ms Memory:5772 kb ****************************************************************/ #inc

【BZOJ 1150】 1150: [CTSC2007]数据备份Backup (贪心+优先队列)

1150: [CTSC2007]数据备份Backup Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公 楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网 络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味 着你仅

【BZOJ 2823】 [AHOI2012]信号塔

2823: [AHOI2012]信号塔 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 469  Solved: 198 [Submit][Status][Discuss] Description 在野外训练中,为了确保每位参加集训的成员安全,实时的掌握和收集周边环境和队员信息非常重要,集训队采用的方式是在训练所在地散布N个小型传感器来收集并传递信息,这些传感器只与设在集训地中的信号塔进行通信,信号塔接收信号的覆盖范围是圆形,可以接收到所有分布在

【BZOJ 3190】 [JLOI2013]赛车

3190: [JLOI2013]赛车 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 803 Solved: 279 [Submit][Status][Discuss] Description 这里有一辆赛车比赛正在进行,赛场上一共有N辆车,分别称为个g1,g2--gn.赛道是一条无限长的直线.最初,gi位于距离起跑线前进ki的位置.比赛开始后,车辆gi将会以vi单位每秒的恒定速度行驶.在这个比赛过程中,如果一辆赛车曾经处于领跑位置的话(即没有其他