uestc 方老师抢银行

参考的大牛的思路和代码

思路: 每次经过一个强连通分量时,都可以走完该分量从而使抢得的钱最多,可以把每个强连通分量缩点,用总的钱数代表该点的值。然后重新遍历新图,遇到网吧可以更新一下结果。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<string>
  6 #include<queue>
  7 #include<algorithm>
  8 #include<map>
  9 #include<iomanip>
 10 #include<climits>
 11 #include<string.h>
 12 #include<cmath>
 13 #include<stdlib.h>
 14 #include<vector>
 15 #include<stack>
 16 #include<set>
 17 using namespace std;
 18 #define INF 1000000007
 19 #define MAXN 300010
 20 #define Mod 1000007
 21 #define N 100007
 22 #define NN 30
 23 #define sigma_size 3
 24 const int maxn = 6e5 + 10;
 25 using namespace std;
 26 typedef long long LL;
 27 const double pi = acos(-1);
 28
 29 vector<int> G[MAXN], G2[MAXN];
 30 int dfn[N], lowlink[N], instk[N], bel[N], coin[N], iswb[N], wb[N], coin2[N];
 31 int tot, tot2, n, m, dfs_clock, scc_cnt, p, k, res;
 32 int u, v;
 33 stack<int> S;
 34
 35 void Tarjan(int u)
 36 {
 37     dfn[u] = lowlink[u] = ++dfs_clock;
 38     S.push(u);
 39     instk[u] = 1;
 40     for (int i = 0; i < G[u].size(); ++i) {
 41         int v = G[u][i];
 42         if (!dfn[v]) {
 43             Tarjan(v);
 44             lowlink[u] = min(lowlink[u], lowlink[v]);
 45         }
 46         else if (instk[v]) {
 47             lowlink[u] = min(lowlink[u], dfn[v]);
 48         }
 49     }
 50     if (lowlink[u] == dfn[u]) {
 51         scc_cnt++;
 52         int v;
 53         do {
 54             v = S.top();
 55             S.pop();
 56             if (iswb[v]) wb[scc_cnt] = 1;
 57             instk[v] = 0;
 58             coin2[scc_cnt] += coin[v];
 59             bel[v] = scc_cnt;
 60             if (v == p) p = scc_cnt;
 61         } while (v != u);
 62     }
 63 }
 64
 65 void find_scc()
 66 {
 67     for (int i = 1; i <= n; ++i)
 68         if (!dfn[i]) Tarjan(i);
 69 }
 70
 71 void dfs(int u, int sum)
 72 {
 73     sum += coin2[u];
 74     if (wb[u]) res = max(res, sum);
 75     for (int i = 0; i < G2[u].size(); ++i)
 76         dfs(G2[u][i], sum);
 77 }
 78
 79 void init()
 80 {
 81     for (int i = 0; i <= n; ++i) {
 82         G[i].clear();
 83         G2[i].clear();
 84     }
 85     while (!S.empty()) S.pop();
 86     dfs_clock = scc_cnt = 0;
 87     memset(instk, 0, sizeof(instk));
 88     memset(dfn, 0, sizeof(dfn));
 89     memset(iswb, 0, sizeof(iswb));
 90     memset(wb, 0, sizeof(wb));
 91     memset(bel, -1, sizeof(bel));
 92     memset(coin2, 0, sizeof(coin2));
 93     memset(lowlink, 0, sizeof(lowlink));
 94 }
 95
 96 void read()
 97 {
 98     for (int i = 0; i < m; ++i) {
 99         scanf("%d%d", &u, &v);
100         G[u].push_back(v);
101     }
102     for (int i = 1; i <= n; ++i)
103         scanf("%d", &coin[i]);
104     scanf("%d%d", &p, &k);
105     for (int i = 0; i < k; ++i) {
106         scanf("%d", &v);
107         iswb[v] = 1;
108     }
109 }
110
111 void rebuild()
112 {
113     for (int i = 1; i <= n; ++i) {
114         for (int j = 0; j < G[i].size(); ++j) {
115             u = bel[i];
116             v = bel[G[i][j]];
117             if (u != v)
118                 G2[u].push_back(v);
119         }
120     }
121     res = -1;
122     dfs(p, 0);
123     cout << res << endl;
124 }
125
126 void process()
127 {
128     init();
129     read();
130     find_scc();
131     rebuild();
132 }
133
134 int main()
135 {
136     while (cin >> n >> m)
137         process();
138     //system("pause");
139     return 0;
140 }
时间: 2024-12-11 01:19:20

uestc 方老师抢银行的相关文章

UESTC 901 方老师抢银行 --Tarjan求强连通分量

思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大.所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个DAG(有向无环图),然后跑一遍DFS,不断加上遍历点的权值,如果到了网吧,则更新一遍答案,因为可以出去了. 求强连通分量时,如果low[u] == dfn[u],说明形成了一个新的强连通分量,且根为u.具体求强连通分量见:http://www.cnblogs.com/whatbeg/p/377642

uestc 方老师和缘分

关于怎么建图,自己还真是想不出来. 我觉得就是找到每个方老师所在的scc里的所有缘分吧.. 转自http://www.cnblogs.com/whatbeg/p/3765621.html 做法:建图,每个方老师和它想要的缘分之间连一条有向边,然后,在给出的初始匹配中反向建边,即如果第i个方老师现在找到的是缘分u,则建边u->i.这样求出所有的强连通分量,每个强连通分量中方老师和缘分的数目一定是相等的,所以每个方老师一定可以找到与他在同一个强连通分量里的缘分,因为强连通分量中每个点都是可达的,某个

uestc 方老师分身 I

题意有点晕啊.. 水题一道.. 分身去教室的时候是单向的,回来的时候也是单向的,这时候就要反过来跑一遍最短路了.. Dijkstra看着模板写的..sigh~ 要不是渣渣..还是记不住.. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<queue> 7 #incl

uestc 方老师炸弹

转自http://www.cnblogs.com/whatbeg/p/3765625.html Tarjan算法. 1.若u为根,且度大于1,则为割点 2.若u不为根,如果low[v]>=dfn[u],则u为割点(出现重边时可能导致等号,要判重边) 3.若low[v]>dfn[u],则边(u,v)为桥(封死在子树内),不操作. 求割点时,枚举所有与当前点u相连的点v: 1.是重边: 忽略 2.是树边: Tarjan(v),更新low[u]=min(low[u],low[v]); 子树个数cnt

uestc 方老师的分身IV

类似POJ1386,参考的大神的博客 首先明确思路: 是否为连通图(并查集解决) -> 是否存在欧拉路径  ->  是否存在欧拉回路   (是,则选取字典序最小的输出,否则直接输出可行解) 注意区分有向图和无线图存在欧拉路径或者欧拉回路的条件: 无向图: G为连通图,并且G仅有两个奇度节点或者无奇度节点 推论:1.当G是仅有两个奇度节点的连通图时,G的欧拉通路必以此两个结点为端点 2.当G时无奇度结点的连通图时,G必有欧拉回路 3.G为欧拉图(存在欧拉回路)的充分必要条件是G为无奇度节点的连通

uestc 方老师的分身 III 拓扑排序

没什么好说的.. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<queue> 7 #include<algorithm> 8 #include<map> 9 #include<iomanip> 10 #include<cl

uestc 方老师的分身 II

题意:求s到t走过边数大于k的最短路 思路:邻接表实现,用w[u][e]来维护(看的大牛博客),u表示当前点,e表示已经经过多少条边.感觉有点类似DP. 在边数大于k的处理上,发现还是使之等于k(K<=50),节省存储空间. spfa算法实现. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string>

uestc 方老师和农场

转自http://www.cnblogs.com/whatbeg/p/3765624.html 首先将原图中的连通分量缩点,一定可以将原图缩成一棵树的形式,然后统计这棵树的叶子节点个数,答案就是(leaf+1)/2.这里不再证明,可以画个图看一下. (简单说明一下,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的.然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点

UESTC 899 方老师和农场 --双连通分量的构造

首先将原图中的连通分量缩点,一定可以将原图缩成一棵树的形式,然后统计这棵树的叶子节点个数,答案就是(leaf+1)/2.这里不再证明,可以画个图看一下. (简单说明一下,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的.然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起.  --Byvoid) 怎么统计呢?用并查集缩点,可以知道,缩点后留下的边全部是原