HDU 5195 DZY Loves Topological Sorting 拓扑排序

题目链接:

hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5195

bc(中文):http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=573&pid=1002

题解:

1、拓扑排序+贪心

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<queue>
 7 using namespace std;
 8 
 9 const int maxn = 1e5 + 10;
10 const int INF = 0x3f3f3f3f;
11 
12 int n, m, k;
13 
14 struct Node {
15     int v, flag;
16     Node(int v,int flag=0):v(v),flag(flag){}
17     Node() { flag = 0; }
18 };
19 
20 vector<Node> head[maxn];
21 int ind[maxn],done[maxn];
22 
23 void init() {
24     for (int i = 0; i < n; i++) {
25         ind[i] = done[i]=0;
26         head[i].clear();
27     }
28 }
29 
30 int main() {
31     while (scanf("%d%d%d", &n, &m, &k) == 3 && n) {
32         init();
33         for (int i = 0; i < m; i++) {
34             int u, v;
35             scanf("%d%d", &u, &v); u--, v--;
36             ind[v]++;
37             head[u].push_back(Node(v,0));
38         }
39 
40         priority_queue<int> pq;
41 
42         //删边
43         for (int i = n - 1; i >= 0; i--) {
44             if (k >= ind[i]) {
45                 //将i的父亲ui中,满足ui<i,即边(ui,i)删了,这里要注意,对于边(ui,i),ui>i的边,根本不用删
46                 k -= ind[i];
47                 pq.push(i);
48                 for (int j = 0; j < head[i].size(); j++) {
49                     Node &nd = head[i][j];
50                     if (i > nd.v) {
51                         //把边(i,v)删了,拓扑排序的时候不能再走这条边了
52                         nd.flag = 1;
53                         ind[nd.v]--;
54                     }
55                 }
56             }
57         }
58 
59         vector<int> ans;
60         //拓扑排序
61         while (!pq.empty()) {
62             int u = pq.top(); pq.pop();
63             if (done[u]) continue;
64             ans.push_back(u);
65             done[u] = 1;
66             for (int i = 0; i < head[u].size(); i++) {
67                 Node& nd = head[u][i];
68                 if (done[nd.v]||nd.flag) continue;
69                 ind[nd.v]--;
70                 if (ind[nd.v] == 0) pq.push(nd.v);
71             }
72         }
73 
74         printf("%d", ans[0]+1);
75         for (int i = 1; i < ans.size(); i++) printf(" %d", ans[i]+1);
76         printf("\n");
77     }
78     return 0;
79 }
80 /*
81 5 3 1
82 4 3
83 1 3
84 3 2
85 
86 5 3 0
87 4 3
88 1 3
89 3 2
90 */

 2、线段树+贪心

对于节点i,入度为ind[i],则可以这样贪心:对于1<=i<=n,求最大的i使得ind[i]<=k,我们可以把入度数组做成线段树,维护最小入度,二分查找,优先搜右边(右边的i会更大),找到以后,吧对于的子节点vj的入度减1,k-=ind[i]。这样一直做n次就能得到答案。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<vector>
 4 #include<algorithm>
 5 #define lson (o<<1)
 6 #define rson ((o<<1)+1)
 7 #define M (l+(r-l)/2)
 8 using namespace std;
 9 
10 const int maxn = 1e5 + 10;
11 const int INF = 0x3f3f3f3f;
12 
13 int n, m, k;
14 
15 vector<int> head[maxn];
16 int ind[maxn<<2],minv[maxn<<2];
17 
18 int _pos, _v;
19 void update(int o, int l, int r) {
20     if (l==r) {
21         ind[o] += _v;
22         minv[o] = ind[o];
23     }
24     else {
25         if (_pos <= M) update(lson, l, M);
26         else update(rson, M + 1, r);
27         minv[o] = min(minv[lson], minv[rson]);
28     }
29 }
30 
31 void query(int o, int l, int r,int &res) {
32     if (l == r) {
33         if (ind[o] <= k) {
34             k -= ind[o];
35             res = l;
36         }
37     }
38     else {
39         //printf("lson:%d,rson:%d\n",minv[lson],minv[rson]);
40         if (k >= minv[rson]) query(rson, M + 1, r,res);
41         else if (k >= minv[lson]) query(lson, l, M,res);
42     }
43 }
44 
45 void init() {
46     for (int i = 1; i <= n; i++) head[i].clear();
47     memset(ind, 0, sizeof(ind));
48     memset(minv,0,sizeof(minv));
49 }
50 
51 int main() {
52     while (scanf("%d%d%d", &n, &m, &k) == 3 && n) {
53         init();
54         for (int i = 0; i < m; i++) {
55             int u, v;
56             scanf("%d%d", &u, &v);
57             head[u].push_back(v);
58             _pos = v, _v = 1;
59             update(1, 1, n);
60         }
61         //puts("after update");
62         vector<int> ans;
63         for (int i = 0; i < n; i++) {
64             int res;
65             query(1, 1, n, res);
66             //puts("after first qurey!");
67             //printf("res:%d\n", res);
68             ans.push_back(res);
69             for (int j = 0; j < head[res].size(); j++) {
70                 _pos = head[res][j], _v = -1;
71                 update(1, 1, n);
72                 //puts("after first upate");
73             }
74             _pos = res, _v = INF;
75             update(1, 1, n);
76         }
77         //puts("ans is zero");
78         printf("%d", ans[0]);
79         for (int i = 1; i < ans.size(); i++) printf(" %d", ans[i]);
80         printf("\n");
81     }
82     return 0;
83 }

 

转载于:https://www.cnblogs.com/fenice/p/5424673.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值