void-man

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

一个工作流图,只有一个开始节点,多个结束点每个结点有个multi属性:

true:表示其前驱节点必须都完成工作才可进行当前节点工作.

false: 表示其前驱节点有一个完成工作即可进行当前节点工作。

每个节点工作消耗1个工作单位,最终从开始节点,需要最少多少时间可以到任一结束点。

乍一看我以为是网络流类的题目,想着怎么建图啊之类的,后来想下,可以逆向思考这道题。

从结束点开始往前驱点推,如果当前点属性是true,就找前驱点里max的工作时间,如果为false,就找前驱点里min的

最终用得到时间+1就是当前点的工作时间了,由于图是单向的,所以可以当作一棵树来考虑,就成了树形dp了。

mintime数组,表示i点的工作时间,-1表示未计算出或者不可达到。

 1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #define N 105
5 #define MST(a,b) memset(a,b,sizeof(a))
6 #define INF 1e9
7 using namespace std;
8 int T;
9 bool isend[N],multi[N],maps[N][N];
10 int mintime[N],vertex,edge,start,endnum,result,tmp,a,b;
11 void init(){
12 MST(isend,false);
13 MST(maps,0);
14 MST(mintime,-1);
15 result = INF;
16 mintime[start] = 1;
17 }
18 int get_time(int cur){
19 int ans;
20 if(mintime[cur] != -1){
21 return mintime[cur];
22 }
23 if(multi[cur])
24 ans = -1;
25 else
26 ans = INF;
27 for(int i = 0; i < vertex; i++){
28 if(maps[i][cur]){
29 tmp = get_time(i) + 1;
30 if(tmp == 0)continue;
31 if((multi[cur] && tmp > ans )|| (!multi[cur] && tmp < ans))
32 ans = tmp;
33 }
34 }
35 if(ans != -1 && ans != INF)
36 mintime[cur] = ans;
37 return mintime[cur];
38
39 }
40 int main(){
41 freopen("D:\\stu\\HUSTACMContest6\\problem2009\\H\\workflow.in","r",stdin);
42 scanf("%d",&T);
43 while(T--){
44 scanf("%d%d",&vertex,&edge);
45 scanf("%d%d",&start,&endnum);
46 init();
47 for(int i = 0 ;i < endnum;i++){
48 scanf("%d",&a);
49 isend[a] = true;
50 }
51 for(int i = 0 ;i < edge ;i++){
52 scanf("%d%d",&a,&b);
53 maps[a][b] = 1;
54 }
55 for(int i = 0; i < vertex; i++){
56 scanf("%d",&a);
57 multi[i] = a;
58 }
59 for(int i = 0; i < vertex; i++){
60 if(isend[i]){
61 tmp = get_time(i);
62 if(tmp != -1 && tmp < result)
63 result = tmp;
64 }
65 }
66 printf("%d\n",result==INF?-1:result);
67
68
69
70 }
71
72
73 }

 

posted on 2012-01-22 15:19  void-man  阅读(264)  评论(0)    收藏  举报