codeforces 796c Bank Hacking

题意:

有很多家银行,如果一个上线的银行和另一个上线的银行直接相连,那么称这种关系叫相邻;

如果一个上线的银行和另一个上线的银行通过第三个上线银行间接相连,称这种情况为半相邻。

每个银行一开始是上线的并且有一个初始的防卫力量(可能为负数),一个银行被抢劫之后就会下线并且再也不会上线,与它相邻和半相邻的所有上线的银行防卫力量都加一。

一个人要去抢劫银行,首先他会选择一家银行进行抢劫,之后抢劫的银行需要满足以下条件:

1.这家上线的银行与一家下线的银行直接相邻;

2.这家银行的防守值不能超过电脑的攻击值。

问电脑的攻击值最小为多少可以保证抢劫完所有的银行。

思路:

首先理清题意,被抢劫的银行必须与一家下线的银行直接相邻。这个条件十分重要,它保证了每家银行的防守值要么加1,要么加2。

所以,如果一家银行的防守值为x,与它相连的所有银行中的防守值最大为y,不与它相连的所有银行中防守值最大的为z,那么第一次抢劫这家银行的答案就是x,y+1,z+2中的最大值。

所以第一种方法就出来啦,枚举所有的银行作为第一次的抢窃,然后算x,y,z。

这种方法稍不注意就会tle,但是巧妙的利用multiset就可以完美解决这个问题,复杂度为nlog(n),但是常数较大。

第二种方法就对思维的要求比较高。

设防守值的最大为mx,

那么统计与每一个点直接相连的mx和mx-1的点的数量。

有一下三个情况:

1.只有一个mx,并且这个mx与所有的mx-1直接相邻,这时答案就是mx;

2.一个mx与所有的mx直接相邻,这时的答案是mx+1;

3.其他情况mx+2。

需要好好想一想。

方法1代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <iostream>
 5 #include <string>
 6 #include <vector>
 7 #include <set>
 8 using namespace std;
 9 
10 multiset<int> mmp;
11 const int inf = 0x3f3f3f3f;
12 const int N = 3e5 + 10;
13 int a[N];
14 vector<int> g[N];
15 
16 int main()
17 {
18     int n;
19     
20     scanf("%d",&n);
21     
22     for (int i = 1;i <= n;i++)
23     {
24         scanf("%d",&a[i]);
25         mmp.insert(a[i]);
26     }
27     
28     for (int i = 0;i < n - 1;i++)
29     {
30         int x,y;
31         scanf("%d%d",&x,&y);
32         g[x].push_back(y);
33         g[y].push_back(x);
34     }
35     
36     int ans = inf;
37     
38     for (int i = 1;i <= n;i++)
39     {
40         int tmp = a[i];
41         mmp.erase(mmp.find(a[i]));
42         for (int j = 0;j < g[i].size();j++)
43         {
44             int k = a[g[i][j]];
45             mmp.erase(mmp.find(k));
46             tmp = max(k+1,tmp);
47         }
48         if (!mmp.empty()) tmp = max(tmp,*(--mmp.end()) + 2);
49         ans = min(tmp,ans);
50         mmp.insert(a[i]);
51         for (int j = 0;j < g[i].size();j++)
52         {
53             int k = a[g[i][j]];
54             mmp.insert(k);
55         }
56     }
57     
58     printf("%d\n",ans);
59     
60     return 0;
61 }

方法2代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <vector>
 4 #include <algorithm>
 5 using namespace std;
 6 const int inf = 0x3f3f3f3f;
 7 const int N = 3e5 + 10;
 8 int a[N];
 9 vector<int> g[N];
10 
11 int main()
12 {
13     int n;
14     
15     scanf("%d",&n);
16     
17     int maxn = -inf;
18     
19     for (int i = 1;i <= n;i++)
20     {
21         scanf("%d",&a[i]);
22         maxn = max(maxn,a[i]);
23     }
24     
25     for (int i = 0;i < n - 1;i++)
26     {
27         int x,y;
28         scanf("%d%d",&x,&y);
29         g[x].push_back(y);
30         g[y].push_back(x);
31     }
32     
33     int mxd = 0,mx = 0;
34     
35     for (int i = 1;i <= n;i++)
36     {
37         if (a[i] == maxn) mx++;
38         if (a[i] == maxn - 1) mxd++;
39     }
40     
41     bool c = 0,d = 0,e = 0;
42     
43     if (mx == 1)
44     {
45         for (int i = 1;i <= n;i++)
46         {
47             if (a[i] == maxn)
48             {
49                 int cnt = 0;
50                 for (int j = 0;j < g[i].size();j++)
51                 {
52                     int x = a[g[i][j]];
53                     
54                     if (x == maxn - 1) cnt++;
55                 }
56                 if (cnt == mxd) c = 1;
57             }
58         }
59         
60         if (c) return 0*printf("%d",maxn);
61     }
62     
63     for (int i = 1;i <= n;i++)
64     {
65         int cnt = 0;
66         if (a[i] == maxn) cnt++;
67         for (int j = 0;j < g[i].size();j++)
68         {
69             if (a[g[i][j]] == maxn) cnt++;
70         }
71         if (cnt == mx) return 0*printf("%d",maxn + 1);
72     }
73     
74     printf("%d",maxn + 2);
75     
76     return 0;
77 }

 

posted @ 2018-04-12 16:53  qrfkickit  阅读(197)  评论(0编辑  收藏  举报