poj 3160 Father Christmas flymouse (SCC缩点+SPFA求最长路)
2015-06-29 10:21
525 查看
题目大意:一个有向图,每个顶点有一个权值(可正可负),现在从某个顶点出发,求所能获得的最大权值。当经过某个顶点时可以选择加上该顶点的权值或者不加,且一个顶点的权值只能够被加一次,顶点可重复访问。
建模:显然对于权为负的顶点是不加的,对于一个强连通分支,要使获得的权值最大,所有的正权都应当算上。于是可以把原图进行缩点,对于每一个强连通分量其权值为内部点的正权值之和。缩点后得到一个DAG图,用SPFA求最长路即可。这里有个技巧,就是加一个源点,另其权值为0,对于DAG图每个顶点连一条边。这样只需以该源点为起点,求一次SPFA就可以得到从各个顶点出发获得的最大值。
建模:显然对于权为负的顶点是不加的,对于一个强连通分支,要使获得的权值最大,所有的正权都应当算上。于是可以把原图进行缩点,对于每一个强连通分量其权值为内部点的正权值之和。缩点后得到一个DAG图,用SPFA求最长路即可。这里有个技巧,就是加一个源点,另其权值为0,对于DAG图每个顶点连一条边。这样只需以该源点为起点,求一次SPFA就可以得到从各个顶点出发获得的最大值。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<stack> #include<queue> using namespace std; #define N 30005 struct Edge{ int to,next; }edge[150005]; int cnt,head ,low ,dfn ,dfs_clock,scc_cnt,sccno ,val ,v ; vector<int>scc ; stack<int>S; void dfs(int u){ low[u]=dfn[u]=++dfs_clock; S.push(u); for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].to; if(!dfn[v]){ dfs(v); low[u]=min(low[v],low[u]); } else if(!sccno[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ val[++scc_cnt]=max(0,v[u]); for(;;){ int x=S.top();S.pop(); sccno[x]=scc_cnt; if(x==u) break; val[scc_cnt]+=max(0,v[x]); } } } void find_scc(int n){ memset(sccno,0,sizeof(sccno)); memset(dfn,0,sizeof(dfn)); dfs_clock=scc_cnt=0; for(int i=0;i<n;++i) if(!dfn[i]) dfs(i); } inline void add(int u,int v){ edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } vector<int>G ; bool inq ; int d ; void spfa(int s){ queue<int>q; memset(inq,0,sizeof(inq)); memset(d,0,sizeof(d)); inq[s]=1;q.push(s); while(!q.empty()){ int u=q.front();q.pop(); inq[u]=0; for(int i=0;i<G[u].size();++i){ int v=G[u][i]; if(d[u]+val[v]>d[v]){ d[v]=d[u]+val[v]; if(!inq[v]){ inq[v]=1; q.push(v); } } } } } int main() { int i,j,n,m,x,y; while(~scanf("%d%d",&n,&m)){ memset(head,-1,sizeof(head)); cnt=0; for(i=0;i<n;++i) scanf("%d",&v[i]); for(i=0;i<m;++i){ scanf("%d%d",&x,&y); add(x,y); } find_scc(n); for(i=1;i<=scc_cnt;++i) {G[i].clear();d[i]=-1;} for(i=0;i<n;++i) for(j=head[i];~j;j=edge[j].next){ int v=edge[j].to; if(sccno[i]!=sccno[v]) G[sccno[i]].push_back(sccno[v]); } for(i=1;i<=scc_cnt;++i) G[scc_cnt+1].push_back(i); int ans=-1; spfa(scc_cnt+1); for(i=1;i<=scc_cnt;++i) ans=max(ans,d[i]); printf("%d\n",ans); } return 0; }
相关文章推荐
- 新锐房地产销售管理系统(部分流程)技术解析(十) 销售管理_销售优惠设置
- MySQL分表
- 免安装sql使用
- [转]IO - 同步,异步,阻塞,非阻塞
- Java基础:字符串
- JavaScript实现把数字转换成中文
- win10预览版10151简体中文iso镜像下载地址(64位)
- java如何实现系统监控、系统信息收集、sigar开源API的学习
- eclipse svn 修改了类名之后提交
- inux读取ISO文件或是光驱的方法--挂载
- Web前端从入门到精通-3 html简介
- oracle数据库敏感操作前创建还原点
- JPA中的@MappedSuperclass
- 需求图形化分析模型
- 在Linux系统中将Redmine和SVN整合入Nginx的方法
- ORA-03113数据库无法正常启动
- 原码, 反码, 补码 详解
- MFC的CString使用
- Linux 常用命令 总结
- Java基础:泛型及其擦除性、不可协变性