本题的题意为 给n个点m条单向边 然后再给出0~n个点的点权(有正有负)
要求是 从某一点开始走,走到一个点:可以选择进去,获得点权(只能进一次)或者选择绕过这个点继续走,求能获得的最大权值
我的做法:强连通缩点+bfs
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <set> #include <vector> #include <map> #include <queue> #include <set> #include <algorithm> using namespace std; #define TMAXN 30010 vector <int> e[TMAXN]; vector <int> e1[TMAXN]; int dfn[TMAXN],low[TMAXN],stack[TMAXN],bleg[TMAXN]; int top,times,n; void tarjan_x(int u){ dfn[u]=low[u]=++times; stack[++top]=u; for(int i=0;i<(int)e[u].size();i++){ int v=e[u][i]; if(!dfn[v]){ tarjan_x(v); low[u]=min(low[u],low[v]); } else if(!bleg[v]) low[u]=min(low[u],low[v]); } if(dfn[u]==low[u]){ bleg[0]++; do{ bleg[stack[top]]=bleg[0]; }while(stack[top--]!=u); } } void initstat(){ memset(dfn,0,sizeof(dfn)); memset(bleg,0,sizeof(bleg)); top=times=0; } void tarjan(int n){ initstat(); for(int i=1;i<=n;i++) if(!dfn[i])tarjan_x(i); } void inite(){ for(int i=0;i<TMAXN;i++)e[i].clear(); for(int i=0;i<TMAXN;i++)e1[i].clear(); } #define INF_MAX -0x7fffffff int val[TMAXN]; int vall[TMAXN]; int dis[TMAXN]; queue <int> q; int bfs(int u){ while(!q.empty())q.pop(); q.push(u); dis[u]=vall[u]; int mm=INF_MAX; while(!q.empty()){ int now=q.front(); q.pop(); if(dis[now]>mm)mm=dis[now]; for(int i=0;i<(int)e1[now].size();i++){ int next=e1[now][i]; if(dis[now]+vall[next]>dis[next]){ dis[next]=dis[now]+vall[next]; q.push(next); } } } return mm; } int main() { int n,m; while(~scanf("%d%d",&n,&m)){ inite(); for(int i=1;i<=n;i++){ scanf("%d",&val[i]); } for(int i=0,x,y;i<m;i++){ scanf("%d%d",&x,&y); e[x+1].push_back(y+1); } tarjan(n); memset(vall,0,sizeof(vall)); for(int i=1;i<=n;i++){ if(val[i]>0) vall[bleg[i]]+=val[i]; for(int j=0;j<(int)e[i].size();j++){ int v=e[i][j]; if(bleg[i]!=bleg[v]){ e1[bleg[i]].push_back(bleg[v]); } } } for(int i=0;i<TMAXN;i++){ dis[i]=INF_MAX; } int mm=INF_MAX; for(int i=1;i<=bleg[0];i++){ if(dis[i]==INF_MAX){ int t=bfs(i); if(t>mm)mm=t; } } printf("%d\n",mm); } return 0; }
|