【APIO2009】BZOJ1179 BSOJ2468 CODEVS1611 抢掠计划
2016-10-08 22:06
295 查看
2468 -- 【APIO2009】抢掠计划
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的单向的道路到达其中的至少一个酒吧。
题解:
很明显这道题目有环,所以缩点之后做图上的DAG或者SPFA都是可以的。
但是要卡递归Tarjan,简直丧心病狂,不想写了。贴一个别人的非递归吧。但是也有神犇莫名就用递归过了,奇怪。
如果非要加一些神秘优化的话,可以考虑倒着Tarjan和在Tarjan前面加inline,不过多半是无济于事的(说要卡就要卡。。。)
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的单向的道路到达其中的至少一个酒吧。
题解:
很明显这道题目有环,所以缩点之后做图上的DAG或者SPFA都是可以的。
但是要卡递归Tarjan,简直丧心病狂,不想写了。贴一个别人的非递归吧。但是也有神犇莫名就用递归过了,奇怪。
如果非要加一些神秘优化的话,可以考虑倒着Tarjan和在Tarjan前面加inline,不过多半是无济于事的(说要卡就要卡。。。)
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<stack> #include<algorithm> #define Maxn 500010 using namespace std; struct line{ int fr,to,next; }p[Maxn]; int tot,n,head[Maxn],val[Maxn]; int dfn[Maxn],low[Maxn],belong[Maxn],in[Maxn],st[Maxn]; int cnt[Maxn],rd[Maxn],dp[Maxn]; int tmpdfn,top,scc; vector<int> dv[Maxn]; void addedge(int u,int v){ p[tot].to=v; p[tot].fr=u; p[tot].next=head[u]; head[u]=tot++; } /********************递归版****************************************** void tarjan(int u){ dfn[u]=low[u]=++tmpdfn; st[top++]=u; in[u]=1; for(int i=head[u];i!=-1;i=p[i].next){ int v=p[i].to; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(in[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ scc++; do{ belong[st[top-1]]=scc; in[st[top-1]]=0; cnt[scc]+=val[st[top-1]]; }while(st[--top]!=u); } } *********************************************************************/ /***非递归版本***/ stack<int> ss; int nx[Maxn]; //下一个儿子 int lx[Maxn]; //上一个儿子 void tarjan(int u){ while(!ss.empty()) ss.pop();//清空栈 ss.push(u); for(int i=1;i<=n;i++) nx[i]=head[i],lx[i]=-1;//nx[i]:i点的头指针,lx[i]:i点的儿子(指向) while(!ss.empty()){ int v=ss.top();//取栈顶*N* if(!dfn[v]){ //第一次访问 dfn[v]=low[v]=++tmpdfn; st[++top]=v; in[v]=1; } if(lx[v]!=-1) low[v]=min(low[v],low[lx[v]]); //访问完儿子 if(nx[v]!=-1){ //有儿子 while(nx[v]!=-1){ //寻找下一个还未访问的儿子 if(!dfn[p[nx[v]].to]){ //树边 lx[v]=p[nx[v]].to;//v的儿子节点 nx[v]=p[nx[v]].next;//头节点转v的邻节点 ss.push(lx[v]);//儿子节点压栈 break;//转到*N*处,相当于递归调用tarjan(lx[v); } else if(in[p[nx[v]].to]) //回边 low[v]=min(low[v],dfn[p[nx[v]].to]); nx[v]=p[nx[v]].next;//头节点转v的邻节点 } } else{ //全部儿子访问完毕 if(low[v]==dfn[v]){ scc++; do{ belong[st[top]]=scc; in[st[top]]=0; cnt[scc]+=val[st[top]]; }while(st[top--]!=v); } ss.pop(); } } } int dfs(int u){//DAG图求最大值,图上的DP int &ans=dp[u]; if(ans) return ans; for(int i=0;i<dv[u].size();i++) ans=max(ans,dfs(dv[u][i])); if(!ans) return ans=rd[u]?cnt[u]:0; return ans+=cnt[u]; } int main() { int m,a,b,s,num; while(cin>>n>>m){ tot=0; memset(head,-1,sizeof head); for(int i=0;i<m;i++){ scanf("%d%d",&a,&b); addedge(a,b); } for(int i=1;i<=n;i++) scanf("%d",val+i); memset(dfn,0,sizeof dfn); memset(in,0,sizeof in); memset(cnt,0,sizeof cnt); scc=0; for(int i=1;i<=n;i++){ tmpdfn=top=0; if(!dfn[i]) tarjan(i); } //缩点建新图 for(int i=1;i<=n;i++) dv[i].clear(); for(int i=1;i<=n;i++) for(int j=head[i];j!=-1;j=p[j].next){ if(belong[p[j].fr]!=belong[p[j].to]) dv[belong[p[j].fr]].push_back(belong[p[j].to]); } for(int i=1;i<=scc;i++){ sort(dv[i].begin(),dv[i].end()); dv[i].erase(unique(dv[i].begin(),dv[i].end()),dv[i].end()); } scanf("%d%d",&s,&num); memset(rd,0,sizeof rd); for(int i=1;i<=num;i++){ scanf("%d",&a); rd[belong[a]]=1; } memset(dp,0,sizeof dp); cout<<dfs(belong[s])<<endl; } return 0; }
相关文章推荐
- BZOJ1179_APIO2009_抢掠计划_C++
- 【Bzoj1179】[Apio2009]抢掠计划atm
- 【bzoj1179】[Apio2009]抢掠计划atm 强连通分量缩点+spfa
- 【日常学习】【强连通分量tarjan缩点】codevs1611 抢掠计划题解
- CodeVS1611_APIO2009_抢掠计划_C++
- BZOJ1179 [APIO2009] ATM
- BZOJ1179 [Apio2009]Atm
- bzoj 1179: [Apio2009]Atm(Trajan+SPFA)
- [bzoj1179][Apio2009]Atm Tarjan+spfa
- 有趣的数列 [Codevs 2337,Bzoj 1485,HNOI2009]
- acmore|acmore.cc1211采油区域1212会议中心1213抢掠计划APIO2009
- 省选专练APIO2009抢掠计划
- [BZOJ1179] [Apio2009]Atm(tarjan缩点 + spfa)
- P2255【L1 SOLO 第五场 APIO2009】抢掠计划
- bzoj 1179: [Apio2009]Atm【tarjan+spfa】
- BZOJ1179 [Apio2009] Atm
- BZOJ1179 [Apio2009]Atm
- 【Apio2009】Bzoj1179 Atm
- [BZOJ 1179][APIO 2009]Atm
- Tarjan缩点+Spfa最长路【p3627】[APIO2009] 抢掠计划