Hdu--5098(拓扑排序 or DP,贪心)

2014-11-02 19:20:31

思路:好题!这道题在邀请赛的时候想了1小时,只想到肯定是拓扑序,没有深究。回来请教了bin神和YYN,分别得到的两种思路:

  bin神:普通的拓扑排序用了一个队列,而现在用两个队列q1,q2分别来存 不需要重启的software 和 需要重启的software。根据题目输入建好图后,按照拓扑序规则,首先将入度的0的点加进队列,当然不需要重启的进q1,需要的进q2。然后处理q1中的所有节点(即要删除这些点),那么要让与他们相连的节点的入度减1,如果发现减完入度为0,再判断其是否需要重启,并加进q1 or q2。一旦发现q1为空,那么使答案加1(即重启一次),把q2中所有元素加入q1,q2清空。如此循环直到q1,q2均为空即可。

  YYN:建图同上,在建完的DAG图中求最长路,然后需要重启的点权为1,不需要的为0。这样找出最长路的权和即可。易证:只有具有从属关系的重启需要分别进行,不然可以同时搞掉。这样需要对每个入度为0的点求一次这样的最长路,取最大值即可,具体方法用DP可解。

 (1)双队列版:(QAQ,一开始WA到死,后来问了bin神才知道ver[maxn * maxn]开成了ver[maxn],简直被自己蠢哭了,以后坚决不犯这样的低级错误,检查代码一定要仔细!)

  1 /*************************************************************************
  2     > File Name: i.cpp
  3     > Author: Nature
  4     > Mail: 564374850@qq.com
  5     > Created Time: Sun 02 Nov 2014 01:36:00 PM CST
  6 ************************************************************************/
  7 
  8 #include <cstdio>
  9 #include <cstring>
 10 #include <cstdlib>
 11 #include <cmath>
 12 #include <vector>
 13 #include <map>
 14 #include <set>
 15 #include <sstream>
 16 #include <string>
 17 #include <stack>
 18 #include <queue>
 19 #include <iostream>
 20 #include <algorithm>
 21 using namespace std;
 22 #define lp (p << 1)
 23 #define rp (p << 1|1)
 24 #define getmid(l,r) (l + (r - l) / 2)
 25 #define MP(a,b) make_pair(a,b)
 26 typedef long long ll;
 27 const int INF = 1 << 30;
 28 const int maxn = 1010;
 29 
 30 int n,m,cnt;
 31 int din[maxn],dout[maxn],reb[maxn];
 32 int vis[maxn],first[maxn],next[maxn * maxn],ver[maxn * maxn],ecnt;
 33 string s,id1,id2;
 34 char name[1500];
 35 map< string,int > mp;
 36 queue<int> q1,q2;
 37 
 38 void Add_edge(int u,int v){
 39     next[++ecnt] = first[u];
 40     ver[ecnt] = v;
 41     first[u] = ecnt;
 42 }
 43 
 44 void Init(){
 45     memset(reb,0,sizeof(reb));
 46     memset(vis,0,sizeof(vis));
 47     memset(din,0,sizeof(din));
 48     memset(dout,0,sizeof(dout));
 49     memset(first,-1,sizeof(first));
 50     while(!q1.empty()) q1.pop();
 51     while(!q2.empty()) q2.pop();
 52     ecnt = cnt = 0;
 53     mp.clear();
 54 }
 55 
 56 int Topo_count(){
 57     for(int i = 1; i <= cnt; ++i) if(din[i] == 0){
 58         if(reb[i] == 0) q1.push(i);
 59         else q2.push(i);
 60     }
 61     int res = 0;
 62     while(!q1.empty() || !q2.empty()){
 63         if(q1.empty() && !q2.empty()){
 64             ++res;
 65             while(!q2.empty()){
 66                 int x = q2.front(); q2.pop();
 67                 q1.push(x);
 68             }
 69         }
 70         while(!q1.empty()){
 71             int x = q1.front(); q1.pop();
 72             vis[x] = 1;
 73             for(int i = first[x]; i != -1; i = next[i]){
 74                 int v = ver[i];
 75                 din[v]--;
 76                 if(din[v] == 0){
 77                     if(!reb[v]) q1.push(v);
 78                     else q2.push(v);
 79                 }
 80             }
 81         }
 82     }
 83     return res;
 84 }
 85 
 86 int main(){
 87     int a,b,len,flag;
 88     scanf("%d",&n);
 89     getchar();
 90     getchar();
 91     for(int Case = 1; Case <= n; ++Case){
 92         Init();
 93         while(getline(cin,s) != NULL){
 94              if(s[0] == '\0')
 95                  break;
 96              istringstream sin(s);
 97              sin >> name;
 98              flag = 0;
 99              int len = strlen(name);
100              for(int i = 0; i < len; ++i)
101                  if(name[i] == '*') flag = 1;
102              name[len - 1 - flag] = '\0';
103              id1 = name;
104              if(mp.find(id1) == mp.end())
105                 mp[id1]= ++cnt;
106              reb[mp[id1]] = flag;
107              while(sin >> id2){
108                  if(mp.find(id2) == mp.end())
109                      mp[id2] = ++cnt;
110                  Add_edge(mp[id2],mp[id1]);
111                  dout[mp[id2]]++;
112                  din[mp[id1]]++;
113              }
114         }
115            printf("Case %d: %d\n",Case,Topo_count());
116     }
117     return 0;
118 }

(2)DP版:裸的记忆化搜索找DAG最长路

  1 /*************************************************************************
  2     > File Name: i.cpp
  3     > Author: Nature
  4     > Mail: 564374850@qq.com
  5     > Created Time: Sun 02 Nov 2014 01:36:00 PM CST
  6 ************************************************************************/
  7 
  8 #include <cstdio>
  9 #include <cstring>
 10 #include <cstdlib>
 11 #include <cmath>
 12 #include <vector>
 13 #include <map>
 14 #include <set>
 15 #include <sstream>
 16 #include <string>
 17 #include <stack>
 18 #include <queue>
 19 #include <iostream>
 20 #include <algorithm>
 21 using namespace std;
 22 #define lp (p << 1)
 23 #define rp (p << 1|1)
 24 #define getmid(l,r) (l + (r - l) / 2)
 25 #define MP(a,b) make_pair(a,b)
 26 typedef long long ll;
 27 const int INF = 1 << 30;
 28 const int maxn = 1010;
 29 
 30 int n,m,cnt;
 31 int din[maxn],reb[maxn],dp[maxn];
 32 int vis[maxn],first[maxn],next[maxn * maxn],ver[maxn * maxn],ecnt;
 33 string s,id1,id2;
 34 char name[1500];
 35 map< string,int > mp;
 36 
 37 void Add_edge(int u,int v){
 38     next[++ecnt] = first[u];
 39     ver[ecnt] = v;
 40     first[u] = ecnt;
 41 }
 42 
 43 void Init(){
 44     memset(reb,0,sizeof(reb));
 45     memset(din,0,sizeof(din));
 46     memset(first,-1,sizeof(first));
 47     ecnt = cnt = 0;
 48     mp.clear();
 49 }
 50 
 51 int Solve(int p){
 52     if(dp[p]) return dp[p];
 53     int ans = 0;
 54     for(int i = first[p]; i != -1; i = next[i]){
 55         int v = ver[i];
 56         ans = max(ans,Solve(v));
 57     }
 58     return dp[p] = ans + reb[p];
 59 }
 60 
 61 int DAG_max(){
 62     memset(dp,0,sizeof(dp));
 63     int ans = 0;
 64     for(int i = 1; i <= cnt; ++i)
 65         if(din[i] == 0)
 66             ans = max(ans,Solve(i));
 67     return ans;
 68 }
 69 
 70 int main(){
 71     int a,b,len,flag;
 72     scanf("%d",&n);
 73     getchar();
 74     getchar();
 75     for(int Case = 1; Case <= n; ++Case){
 76         Init();
 77         while(getline(cin,s) != NULL){
 78              if(s[0] == '\0')
 79                  break;
 80              istringstream sin(s);
 81              sin >> name;
 82              flag = 0;
 83              int len = strlen(name);
 84              for(int i = 0; i < len; ++i)
 85                  if(name[i] == '*') flag = 1;
 86              name[len - 1 - flag] = '\0';
 87              id1 = name;
 88              if(mp.find(id1) == mp.end())
 89                 mp[id1]= ++cnt;
 90              reb[mp[id1]] = flag;
 91              while(sin >> id2){
 92                  if(mp.find(id2) == mp.end())
 93                      mp[id2] = ++cnt;
 94                  Add_edge(mp[id2],mp[id1]);
 95                  din[mp[id1]]++;
 96              }
 97         }
 98            printf("Case %d: %d\n",Case,DAG_max());
 99     }
100     return 0;
101 }

 

posted @ 2014-11-02 19:45  Naturain  阅读(594)  评论(0编辑  收藏  举报