poj 3160 Father Christmas flymouse 【SCC缩点 + 虚拟源点SPFA求最长路】
2015-08-09 19:04
477 查看
Father Christmas flymouse
Description
After retirement as contestant from WHU ACM Team, flymouse volunteered to do the odds and ends such as cleaning out the computer lab for training as extension of his contribution to the team. When Christmas came, flymouse played Father Christmas to give
gifts to the team members. The team members lived in distinct rooms in different buildings on the campus. To save vigor, flymouse decided to choose only one of those rooms as the place to start his journey and follow directed paths to visit one room after
another and give out gifts en passant until he could reach no more unvisited rooms.
During the days on the team, flymouse left different impressions on his teammates at the time. Some of them, like LiZhiXu, with whom flymouse shared a lot of candies, would surely sing flymouse’s deeds of generosity, while the others, like snoopy, would
never let flymouse off for his idleness. flymouse was able to use some kind of comfort index to quantitize whether better or worse he would feel after hearing the words from the gift recipients (positive for better and negative for worse). When arriving at
a room, he chould choose to enter and give out a gift and hear the words from the recipient, or bypass the room in silence. He could arrive at a room more than once but never enter it a second time. He wanted to maximize the the sum of comfort indices accumulated
along his journey.
Input
The input contains several test cases. Each test cases start with two integers N and M not exceeding 30 000 and 150 000 respectively on the first line, meaning that there were N team members living in N distinct rooms
andM direct paths. On the next N lines there are N integers, one on each line, the i-th of which gives the comfort index of the words of the team member in the i-th room. Then follow M lines, each containing
two integers i and jindicating a directed path from the i-th room to the j-th one. Process to end of file.
Output
For each test case, output one line with only the maximized sum of accumulated comfort indices.
Sample Input
Sample Output
Hint
32-bit signed integer type is capable of doing all arithmetic.
差不多一个多星期没看SCC了,今天碰到与SCC有关的题目,没想到纯手写后1A了。好激动!
题意:有N个屋子以及连接屋子的M条有向边,每个屋子都有一个舒适指数(可正可负)。起始舒适指数为0,你可以任选一个屋子当作起点并且可以走一个屋子多次,但最多获取屋子的舒适指数一次(对于一个屋子的舒适指数可以选择获取或者不获取)。问你在这个过程中所能获得的最大舒适指数。
把N个屋子虚拟成N个点。
分析:若以任一个SCC里面舒适指数为非负的屋子为起点,无论怎样我们至少能获取这个SCC里面所有为正的舒适指数(要理解)。这也就意味着,每个SCC的舒适指数可以用这个SCC里面所有为正的舒适指数之和来表示。到这里,就可以把问题转化成:有向图SCC缩点后,用SCC的舒适指数建边,求以任一个SCC为起点 所能跑出的最长路。
思路:用used数组记录每个SCC的最大舒适指数,用dist数组存储虚拟源点0到节点的最远距离。
一:对有向图求出所有的SCC。
二:求出每个SCC的used值。(累加所有为正的舒适指数)
三:缩点并对每<u,v>边 建立边权used[v]。
四:设置虚拟源点0,连接所有的SCC,边权为对应SCC的used值。
五:以0为源点跑一次SPFA,对dist数组排序后,输出最大的dist值。
AC代码:
Time Limit: 1000MS | Memory Limit: 131072K | |
Total Submissions: 2971 | Accepted: 1007 |
After retirement as contestant from WHU ACM Team, flymouse volunteered to do the odds and ends such as cleaning out the computer lab for training as extension of his contribution to the team. When Christmas came, flymouse played Father Christmas to give
gifts to the team members. The team members lived in distinct rooms in different buildings on the campus. To save vigor, flymouse decided to choose only one of those rooms as the place to start his journey and follow directed paths to visit one room after
another and give out gifts en passant until he could reach no more unvisited rooms.
During the days on the team, flymouse left different impressions on his teammates at the time. Some of them, like LiZhiXu, with whom flymouse shared a lot of candies, would surely sing flymouse’s deeds of generosity, while the others, like snoopy, would
never let flymouse off for his idleness. flymouse was able to use some kind of comfort index to quantitize whether better or worse he would feel after hearing the words from the gift recipients (positive for better and negative for worse). When arriving at
a room, he chould choose to enter and give out a gift and hear the words from the recipient, or bypass the room in silence. He could arrive at a room more than once but never enter it a second time. He wanted to maximize the the sum of comfort indices accumulated
along his journey.
Input
The input contains several test cases. Each test cases start with two integers N and M not exceeding 30 000 and 150 000 respectively on the first line, meaning that there were N team members living in N distinct rooms
andM direct paths. On the next N lines there are N integers, one on each line, the i-th of which gives the comfort index of the words of the team member in the i-th room. Then follow M lines, each containing
two integers i and jindicating a directed path from the i-th room to the j-th one. Process to end of file.
Output
For each test case, output one line with only the maximized sum of accumulated comfort indices.
Sample Input
2 2 14 21 0 1 1 0
Sample Output
35
Hint
32-bit signed integer type is capable of doing all arithmetic.
差不多一个多星期没看SCC了,今天碰到与SCC有关的题目,没想到纯手写后1A了。好激动!
题意:有N个屋子以及连接屋子的M条有向边,每个屋子都有一个舒适指数(可正可负)。起始舒适指数为0,你可以任选一个屋子当作起点并且可以走一个屋子多次,但最多获取屋子的舒适指数一次(对于一个屋子的舒适指数可以选择获取或者不获取)。问你在这个过程中所能获得的最大舒适指数。
把N个屋子虚拟成N个点。
分析:若以任一个SCC里面舒适指数为非负的屋子为起点,无论怎样我们至少能获取这个SCC里面所有为正的舒适指数(要理解)。这也就意味着,每个SCC的舒适指数可以用这个SCC里面所有为正的舒适指数之和来表示。到这里,就可以把问题转化成:有向图SCC缩点后,用SCC的舒适指数建边,求以任一个SCC为起点 所能跑出的最长路。
思路:用used数组记录每个SCC的最大舒适指数,用dist数组存储虚拟源点0到节点的最远距离。
一:对有向图求出所有的SCC。
二:求出每个SCC的used值。(累加所有为正的舒适指数)
三:缩点并对每<u,v>边 建立边权used[v]。
四:设置虚拟源点0,连接所有的SCC,边权为对应SCC的used值。
五:以0为源点跑一次SPFA,对dist数组排序后,输出最大的dist值。
AC代码:
#include <cstdio> #include <cstring> #include <queue> #include <vector> #include <stack> #include <algorithm> #define MAXN 150000+100 #define MAXM 300000+1000 using namespace std; struct Edge { int from, to, next; }; Edge edge[MAXM]; int head[MAXN], edgenum; int low[MAXN], dfn[MAXN]; int dfs_clock; int sccno[MAXN], scc_cnt; vector<int> scc[MAXN];//存储每个SCC的点 stack<int> S;//存储当前SCC的点 bool Instack[MAXN]; int N, M; int com[MAXN];//存储进入每个房间的舒适指数 void init() { edgenum = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v) { Edge E = {u, v, head[u]}; edge[edgenum] = E; head[u] = edgenum++; } void getMap() { int a, b; for(int i = 1; i <= N; i++) scanf("%d", &com[i]); while(M--) { scanf("%d%d", &a, &b); a++, b++; addEdge(a, b); } } void tarjan(int u, int fa) { int v; low[u] = dfn[u] = ++dfs_clock; S.push(u); Instack[u] = true; for(int i = head[u]; i != -1; i = edge[i].next) { v = edge[i].to; if(!dfn[v]) { tarjan(v, u); low[u] = min(low[u], low[v]); } else if(Instack[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]) { scc_cnt++; scc[scc_cnt].clear(); for(;;) { v = S.top(); S.pop(); Instack[v] = false; sccno[v] = scc_cnt; scc[scc_cnt].push_back(v); if(v == u) break; } } } void find_cut(int l, int r) { memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(sccno, 0, sizeof(sccno)); memset(Instack, false, sizeof(Instack)); dfs_clock = scc_cnt = 0; for(int i = l; i <= r; i++) if(!dfn[i]) tarjan(i, -1); } struct IT//求最长路 { int from, to, val, next; }; IT it[MAXM]; int head1[MAXN], edgenum1; int used[MAXN];//存储每个SCC里面的正权舒适指数 int dist[MAXN];//源点到节点的最长距离 bool vis[MAXN];//标记是否入队 void addIT(int u, int v, int w) { IT E = {u, v, w, head1[u]}; it[edgenum1] = E; head1[u] = edgenum1++; } void suodian()//缩点建新图 { edgenum1 = 0; memset(head1, -1, sizeof(head1)); for(int i = 0; i < edgenum; i++) { int u = sccno[edge[i].from]; int v = sccno[edge[i].to]; if(u != v) addIT(u, v, used[v]); } //设置虚拟源点 0 for(int i = 1; i <= scc_cnt; i++) addIT(0, i, used[i]); } void SPFA(int sx)//跑最长路 { queue<int> Q; memset(dist, 0, sizeof(dist)); memset(vis, false, sizeof(vis)); vis[sx] = true; Q.push(sx); while(!Q.empty()) { int u = Q.front(); Q.pop(); vis[u] = false; for(int i = head1[u]; i != -1; i = it[i].next) { IT E = it[i]; if(dist[E.to] < dist[u] + E.val) { dist[E.to] = dist[u] + E.val; if(!vis[E.to]) { vis[E.to] = true; Q.push(E.to); } } } } } void solve() { //先统计每个SCC里面的正权舒适指数 for(int i = 1; i <= scc_cnt; i++) { int sum = 0; for(int j = 0; j < scc[i].size(); j++) { if(com[scc[i][j]] > 0) sum += com[scc[i][j]]; } used[i] = sum; } suodian();//缩点 SPFA(0);//最长路 sort(dist, dist + scc_cnt+1); printf("%d\n", dist[scc_cnt]); } int main() { while(scanf("%d%d", &N, &M) != EOF) { init(); getMap(); find_cut(1, N);//求SCC solve(); } return 0; }
相关文章推荐
- UITableView 及其传值
- Linux防火墙iptables/netfilter(三)
- 随记
- 用VC6扩展CButton类制作风格独特的按钮
- 8.Python基础 面向对象的基本概念
- (大数据工程师学习路径)第一步 Linux 基础入门----正则表达式基础
- 暑假第3周工作周报
- Shader预处理宏、内置状态变量、多版本编译等
- 【Java多线程】之十三:Java Callable Future Example
- 注意:STM32库函数中未用到的参数也一定要初始化
- Python-Selenium2做Web自动化测试(12)-上传文件、下载文件、调用 JavaScript、控制浏览器滚动条
- Android的历史
- 102. Binary Tree Level Order Traversal
- 起码要有两个可选的解决方案
- solr 4.4添加索引是新手容易遇到的有关问题
- 如何在 Java 中正确使用 wait, notify 和 notifyAll – 以生产者消费者模型为例
- 分享一下MinGW和cygwin
- [BZOJ1618] [Usaco2008 Nov]Buying Hay 购买干草
- 【网络流】 POJ 2125 Destroying The Graph
- Java注解之常用注解