/* *State: POJ3160 Accepted 1812K 63MS C++ 3743B *题目大意: * 一个圣诞老人去给n个同学送东西,然后每个同学会给圣诞老人评价(可正负), * 然后n个同学的地址是一个有向有环图,每到一个同学家门口,圣诞老人可以 * 选择进去,或者不进去,圣诞老人走到无路可走为止,然后要求给圣诞老人选 * 一个起点,使得圣诞老人这次旅行获得的权值最大。 *解题思路: * 题意看了好久啊,有向有环图,还可以选择拿权值或者不拿,最终要求总共最 * 大权值,那么可以一开始就给点赋权值,如果权值为负就赋值为0,然后给有向 * 有环图缩点。之后再把缩点后的图入度为0的点都用一个虚拟节点汇点,然后从 * 这个虚拟节点开始用spfa求最长路,最后算一下出度为0的点的最长度的最大值 * 即为所求。 *解题感想: * 其实题目还是挺基础的,只是代码比较长,足足写了200+ rows,然后一开始用 * 树形dp去计算最大值,后来wa了一次画图发现,这样行不通,因为缩点后的图 * 是DAG而不是树形,DAG有可能点是公用的,所以用类似记忆化搜索的树形dp是 * 不行的,相反,转化为最长路却很容易算出答案。 * 最后还是wa了三次,re了一次,re是因为一开始用了向量去存邻接表,发现速度 * 慢得很,就索性改为静态邻接表,有一个地方看错了,不过还好,re很快就查了 * 出来,剩下的wa就够蛋疼的了,一开始是发现初始化少了一些,然后很冲动地 * 交,结果还是wa,后来蛋疼无比之时,发现,汗死我了,我怎么把最长路写成了 * 最短路,我是不是最短路写疯了?一写spfa就写成了最短路,汗死我~~~~~~~~~ * 思维定势的痛楚。不过还是那样,200+的代码,一定要wa一次,很少能1a,但是 * 花点儿时间认真查,还是可以查出来的。 */
View Code
1 #include <iostream> 2 #include <queue> 3 using namespace std; 4 5 const int MAXN = 30005; 6 const int MAXE = 150005; 7 const int inf = 0x3f3f3f3f; 8 9 typedef struct _edge 10 { 11 int v, next; 12 }E; 13 E edge[MAXE]; 14 int cntEdge, head[MAXN]; 15 int myS[MAXN], top; 16 int weight[MAXN], dfn[MAXN], low[MAXN], step; 17 int inS[MAXN], scc, id[MAXN]; 18 19 //缩点,建DAG 20 typedef struct _node 21 { 22 int v, w, next; 23 }N; 24 N sccEdge[MAXE]; 25 int sccHead[MAXN], sccCntEdge; 26 int idw[MAXN], in[MAXN], out[MAXN]; 27 28 void init() 29 { 30 top = 0; 31 step = cntEdge = sccCntEdge = 0; 32 scc = 1; 33 for(int i = 0; i < MAXN; i++) 34 { 35 myS[i] = 0; 36 in[i] = out[i] = 0; 37 weight[i] = 0; 38 id[i] = -1; 39 sccHead[i] = head[i] = -1; 40 inS[i] = idw[i] = 0; 41 dfn[i] = low[i] = -1; 42 } 43 } 44 45 void addEdge(int u, int v) 46 { 47 edge[cntEdge].v = v; 48 edge[cntEdge].next = head[u]; 49 head[u] = cntEdge++; 50 } 51 52 void tarjan_scc(int n) 53 { 54 dfn[n] = low[n] = ++step; 55 myS[top++] = n; 56 inS[n] = 1; 57 for(int f = head[n]; f != -1; f = edge[f].next) 58 { 59 int son = edge[f].v; 60 if(dfn[son] == -1) 61 { 62 tarjan_scc(son); 63 low[n] = min(low[n], low[son]); 64 } 65 else if(inS[son] == 1) 66 low[n] = min(low[n], dfn[son]); 67 } 68 69 if(low[n] == dfn[n] && top != 0) 70 { 71 int tmp; 72 do 73 { 74 tmp = myS[--top]; 75 76 inS[tmp] = 0; 77 id[tmp] = scc; 78 idw[scc] += weight[tmp]; 79 80 }while(top != 0 && tmp != n); 81 scc++; 82 } 83 } 84 85 int spfa(int s) 86 { 87 int dis[MAXN], inQ[MAXN] = {0}; 88 for(int i = 0; i < MAXN; i++) 89 dis[i] = -inf; 90 queue<int> Q; 91 92 Q.push(s); 93 dis[s] = 0; 94 inQ[s] = 1; 95 96 while(!Q.empty()) 97 { 98 int pre = Q.front(); 99 Q.pop(); 100 inQ[pre] = 0; 101 102 for(int i = sccHead[pre]; i != -1; i = sccEdge[i].next) 103 { 104 int son = sccEdge[i].v, w = sccEdge[i].w; 105 if(dis[son] < dis[pre] + w) 106 { 107 dis[son] = dis[pre] + w; 108 if(inQ[son] == 0) 109 { 110 Q.push(son); 111 inQ[son] = 1; 112 } 113 } 114 } 115 } 116 117 int Max = 0; 118 for(int i = 1; i < scc; i++) 119 { 120 if(out[i] == 0) 121 { 122 if(dis[i] > Max) 123 Max = dis[i]; 124 } 125 } 126 return Max; 127 } 128 129 void bulid_scc(int n, int &sol) 130 { 131 int u, v; 132 for(int i = 0; i < n; i++) 133 { 134 for(int j = head[i]; j != -1; j = edge[j].next) 135 { 136 u = i, v = edge[j].v; 137 if(id[u] == id[v]) 138 continue; 139 else 140 { 141 sccEdge[sccCntEdge].v = id[v]; 142 sccEdge[sccCntEdge].w = idw[id[v]]; 143 sccEdge[sccCntEdge].next = sccHead[id[u]]; 144 sccHead[id[u]] = sccCntEdge++; 145 146 in[id[v]]++; 147 out[id[u]]++; 148 } 149 } 150 } 151 152 int Max = 0; 153 for(int i = 1; i < scc; i++) 154 { 155 if(in[i] == 0) 156 { 157 sccEdge[sccCntEdge].v = i; 158 sccEdge[sccCntEdge].w = idw[i]; 159 sccEdge[sccCntEdge].next = sccHead[0]; 160 sccHead[0] = sccCntEdge++; 161 162 } 163 } 164 165 sol = spfa(0); 166 return ; 167 } 168 169 int main(void) 170 { 171 #ifndef ONLINE_JUDGE 172 freopen("in.txt", "r", stdin); 173 #endif 174 175 int n, m; 176 while(scanf("%d %d", &n, &m) == 2) 177 { 178 int u, v, t; 179 init(); 180 for(int i = 0; i < n; i++) 181 { 182 scanf("%d", &t); 183 if(t > 0) 184 weight[i] = t; 185 else 186 weight[i] = 0; 187 } 188 for(int i = 0; i < m; i++) 189 { 190 scanf("%d %d", &u, &v); 191 addEdge(u, v); 192 } 193 for(int i = 0; i < n; i++) 194 { 195 if(dfn[i] == -1) 196 tarjan_scc(i); 197 } 198 int sol; 199 bulid_scc(n, sol); 200 printf("%d\n", sol); 201 } 202 return 0; 203 }