POJ 3592 缩点加spfa
2016-04-08 20:22
399 查看
缩点的最大好处在于把一个杂乱无章的有向图变成一个有向无环图, 而在有向无环图中,有两种点比较特殊:一种是入度为 0 的点,另一种是 出度为 0 的点。我们把入度为0的点就叫做根,出度为0的点叫做叶子!
题意:一辆坦克从N*M矩阵的左上角出发,每次往右或往下走一格,每格可以是’#’(表示不可以走),’*’表示传送门,或者是数字,表示在该格可以获得的值(只能取一次),传送门可以将到达该处的坦克传送到指定位置,你可以选择被传送或者走相邻的格,问坦克可以获得的值的和最大为多少。
分析:题目是说最终能获得的最大值,并没有指定最终要到达的位置;
因为传送门的存在,可能出现环;
算法:邻接表建立有向图;
求原图的强连通分量,缩点后重建有向图;
对重建后的有向图,利用bfs求从原图左上角点(0,0)出发的最长路(没有指定终点)
这题是盗用的人家的代码,写的风格蛮不错的,把输入,targan缩点,重新建图,bfs写的都是蛮清楚的,其中建边的时候对’*’的处理蛮可以的,先读入图,再根据”进行坐标的读入,将二维坐标转化为一维,还要注意坑就是直接跳转的地方有可能是#!!!!
题意:一辆坦克从N*M矩阵的左上角出发,每次往右或往下走一格,每格可以是’#’(表示不可以走),’*’表示传送门,或者是数字,表示在该格可以获得的值(只能取一次),传送门可以将到达该处的坦克传送到指定位置,你可以选择被传送或者走相邻的格,问坦克可以获得的值的和最大为多少。
分析:题目是说最终能获得的最大值,并没有指定最终要到达的位置;
因为传送门的存在,可能出现环;
算法:邻接表建立有向图;
求原图的强连通分量,缩点后重建有向图;
对重建后的有向图,利用bfs求从原图左上角点(0,0)出发的最长路(没有指定终点)
这题是盗用的人家的代码,写的风格蛮不错的,把输入,targan缩点,重新建图,bfs写的都是蛮清楚的,其中建边的时候对’*’的处理蛮可以的,先读入图,再根据”进行坐标的读入,将二维坐标转化为一维,还要注意坑就是直接跳转的地方有可能是#!!!!
#include <iostream> #include <vector> #include <queue> #include <stack> using namespace std; const int MAX_EDGE_NUM = 50000 + 10; const int MAX_POINT_NUM = 2200 + 10; // 假设对边u-->v:v是被指向的点,next是从u出发的下一条边的编号 struct EDGE { int v; int next; }; // 数组g和数组adj联合使用构造有向图(第一次建图) EDGE g[MAX_EDGE_NUM]; int adj[MAX_POINT_NUM]; // 第二次建图使用vector vector<int> vec[MAX_POINT_NUM]; int low[MAX_POINT_NUM]; // low[u]:是u或u的子树能追溯到的最早的栈中的节点的次序号 int dfn[MAX_POINT_NUM]; // dfn[u]:节点u搜索的次序编号(时间戳) int sccf[MAX_POINT_NUM]; // sccf[i]:第i个点所在的强连通分量的编号 int dis[MAX_POINT_NUM]; // dis[i]:从点0到达点i所能获得的最大值 int ores[MAX_POINT_NUM]; // ores[i]:在点i能获得的值 int sum[MAX_POINT_NUM]; // 强连通分量i的煤矿总量 bool ins[MAX_POINT_NUM]; // 是否在栈中 bool inq[MAX_POINT_NUM]; // 是否在队中 int scc; // 强连通分量的个数 int e, index; // 全局临时变量 int n, m; // 点数 边数 stack<int> s; void addEdge(int u, int v) { g[e].v = v; g[e].next = adj[u]; adj[u] = e; e++; } void Init() { for (int i=1; i<=scc; ++i) { vec[i].clear(); } e = scc = 0; index = 1; memset(adj, -1, sizeof(adj)); memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(ins, false, sizeof(ins)); memset(ores, 0, sizeof(ores)); memset(sum, 0, sizeof(sum)); } void RebuildMap() { // 枚举每一个点u for (int u=0; u<n*m; ++u) { // 对每一条原始边 u-->v for (int k=adj[u]; k!=-1; k=g[k].next) { int v = g[k].v; // 新边 sccf[u]-->sccf[v] if (sccf[u] != sccf[v]) { vec[sccf[u]].push_back(sccf[v]); } } } } void Tarjan(int u) { int v; low[u] = dfn[u] = index++; s.push(u); ins[u] = true; // 枚举每一条边 for (int k=adj[u]; k!=-1; k=g[k].next) { v = g[k].v; if (0 == dfn[v]) { Tarjan(v); if (low[v] < low[u]) { low[u] = low[v]; } } else if (ins[v] && dfn[v]<low[u]) { low[u] = dfn[v]; } } // 如果节点u是强连通分量的根 if (dfn[u] == low[u]) { scc++; do { v = s.top(); s.pop(); ins[v]= false; sccf[v] = scc; sum[scc] += ores[v]; }while (u != v); } } // 从第一个点开始求最长路 void Bfs() { memset(inq, false, sizeof(inq)); memset(dis, 0, sizeof(dis)); queue<int> q; q.push(sccf[0]); inq[sccf[0]] = true; dis[sccf[0]] = sum[sccf[0]]; while (!q.empty()) { int u = q.front(); q.pop(); inq[u] = false; // 对边u-->v for (int i=0; i<vec[u].size(); ++i) { int v = vec[u][i]; if (dis[v] < dis[u]+sum[v]) { dis[v] = dis[u] + sum[v]; if (!inq[v]) { inq[v] = true; q.push(v); } } } } } void Input() { char map[45][45]; int r, c, i, j; // 输入原始图 scanf("%d%d", &n, &m); for (i=0; i<n; ++i) { scanf("%s", map[i]); } // 建立有向图 for (i=0; i<n; ++i) { for (j=0; j<m; ++j) { if (map[i][j] != '#') { // 向下走 if (i+1<n && map[i+1][j]!='#') { addEdge(i*m+j, (i+1)*m+j); } // 向右走 if (j+1<m && map[i][j+1]!='#') { addEdge(i*m+j, i*m+j+1); } ores[i*m+j] = map[i][j] - '0'; if ('*' == map[i][j]) { ores[i*m+j] = 0; scanf("%d%d", &r, &c); if ('#' != map[r][c]) { addEdge(i*m+j, r*m+c); } } } } } } int main() { int i, cases; scanf("%d", &cases); while (cases--) { // 数据初始化 Init(); // 输入数据并建立有向图 Input(); // 求强连通分量 for (i=0; i<n*m; ++i) { if (0 == dfn[i]) { Tarjan(i); } } // 求得强连通分量后进行缩点,对缩点后的图利用vector进行重建 RebuildMap(); // 求最长路 Bfs(); // 求得最终答案并输出:最长路 int ans = -1; for (i=1; i<=scc; ++i) { if (dis[i] > ans) { ans = dis[i]; } } printf("%d\n", ans); } return 0; }
相关文章推荐
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1001
- POJ ACM 1002
- 1611:The Suspects
- POJ1089 区间合并
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- 用单调栈解决最大连续矩形面积问题
- 2632 Crashing Robots的解决方法
- 1573 Robot Motion (简单题)
- POJ 1200 Crazy Search(简单哈希)
- 【高手回避】poj3268,一道很水的dijkstra算法题