/*
*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 }
posted on 2012-08-16 08:38  cchun  阅读(284)  评论(0编辑  收藏  举报