球球您帮帮萌新吧呜呜呜
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int MAX=1e5+10,N=1e4+10;
int head[N],cnt,dfn[N],vis[N],low[N];
int n,m,cnt2,cnt3,stac[N],cnt4;
int ind[N],val[N],h[N],va[N];
int fin[N];
struct edge{
int u,v,next;
}ed[MAX],ad[MAX];
queue <int> q;
void add(int u,int v){
ed[++cnt].v=v;
ed[cnt].u=u;
ed[cnt].next=head[u];
head[u]=cnt;
}
void tarjan(int u){
dfn[u]=low[u]=++cnt2;
stac[++cnt3]=u;
vis[u]=1;
for(int i=head[u];i;i=ed[i].next){
int v=ed[i].v;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}else if(vis[v]){
low[u]=min(low[u],low[v]);//相同的根节点 表示缩成一个点
}
}
if(low[u]==dfn[u]){
int y;
while(y=stac[cnt3--]){
vis[stac[cnt3+1]]=0;
va[low[u]]+=val[y];
if(u==y){
break;
}
}
}
}
int topo(){
for(int i=1;i<=n;i++){
if(!ind[i]&&low[i]==dfn[i]){
q.push(low[i]);
fin[low[i]]=va[low[i]];
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=h[u];i;i=ad[i].next){
int v=ad[i].v;
ind[v]--;
fin[v]=max(fin[v],fin[u]+va[v]);
if(!ind[v]){
q.push(v);
}
}
}
int maxx=0;
for(int i=1;i<=n;i++){
maxx=max(maxx,fin[i]);
}
return maxx;
}
int main(){
cin>>n>>m;
int a,b;
for(int i=1;i<=n;i++){
cin>>val[i];
}
for(int i=1;i<=m;i++){
cin>>a>>b;
add(a,b);
}
for(int i=1;i<=n;i++){
if(!dfn[i]){
tarjan(i);
}
}
for(int i=1;i<=cnt;i++){
int u=ed[i].u,v=ed[i].v;
if(low[u]!=low[v]){
ad[++cnt4].u=low[u];
ad[cnt4].v=low[v];
ad[cnt4].next=h[low[u]];
h[low[u]]=cnt4;
}
}
cout<<topo()<<endl;
return 0;
}
下面是另一个ac的版本。。。我感觉是一样的,为什么上面的不对呢?
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int MAX=1e5+10,N=1e4+10;
int head[N],cnt,bj[N],dfn[N],vis[N],low[N];
int n,m,cnt2,cnt3,stac[N],cnt4,total;
int ind[N],val[N],h[N],va[N];
int fin[N];
struct edge{
int u,v,next;
}ed[MAX],ad[MAX];
queue <int> q;
void add(int u,int v){
ed[++cnt].v=v;
ed[cnt].u=u;
ed[cnt].next=head[u];
head[u]=cnt;
}
void tarjan(int u){
dfn[u]=low[u]=++cnt2; //dfn是时间戳,low表示强连通分量的最小点(第一个到的dfn的值)
stac[++cnt3]=u; //把这个数入栈
vis[u]=1; //表示u已入栈
for(int i=head[u];i!=-1;i=ed[i].next){
int v=ed[i].v;
if(!dfn[v]){ //如果v没有跑过(如果没跑过的话dfn是0)
tarjan(v); //继续向下跑
low[u]=min(low[u],low[v]); //跑完之后比较当前的low和v的low哪个更小,
}else if(vis[v]){ //如果跑过了 并且在栈里
low[u]=min(low[u],low[v]); //说明是强连通分量,比较哪个的low更小
}
}
if(low[u]==dfn[u]){ //如果dfn和low相等,说明此时的u就是根节点
int y;
while(y=stac[cnt3--]){ //出栈
vis[stac[cnt3+1]]=0; //不要忘了标记vis=0,表示不在栈里
va[u]+=val[y];
bj[y]=u; //bj[y]是y的祖先节点
if(u==y){ //如果出栈到自己,结束
break;
}
}
}
}
int topo(){ //拓扑排序
for(int i=1;i<=n;i++){
if(!ind[i]&&bj[i]==i){
q.push(bj[i]);
fin[bj[i]]=va[bj[i]]; //fin i的意思是到达缩完点i的最大值
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=h[u];i!=-1;i=ad[i].next){
int v=ad[i].v;
ind[v]--;
fin[v]=max(fin[v],fin[u]+va[v]); //小dp,比较fin u过来 和它本身的fin 哪个大(呜呜没解释清楚)
if(!ind[v]){
q.push(v);
}
}
}
int maxx=0;
for(int i=1;i<=n;i++){ //循环一遍,找最大的fin
maxx=max(maxx,fin[i]);
}
return maxx;
}
int main(){
cin>>n>>m;
memset(head,-1,sizeof(head));
memset(h,-1,sizeof(h));
int a,b;
for(int i=1;i<=n;i++){
cin>>val[i];
}
for(int i=1;i<=m;i++){
cin>>a>>b;
add(a,b);
}
for(int i=1;i<=n;i++){ //每个点开始都tarjan一遍
if(!dfn[i]){ //没有跑过i的话
tarjan(i); //因为可能不止一个图。。。
}
}
for(int i=1;i<=cnt;i++){ //两遍链式前向星
int u=ed[i].u,v=ed[i].v;
if(bj[u]!=bj[v]){ //如果祖先节点不同
ad[++cnt4].u=bj[u];
ad[cnt4].v=bj[v];
ad[cnt4].next=h[bj[u]];
h[bj[u]]=cnt4;
ind[bj[v]]++; //入度++
}
}
cout<<topo()<<endl;
return 0;
}