题目链接:http://codeforces.com/problemset/problem/796/C
题目大意:有n家银行,第一次可以攻击任意一家银行(能量低于自身),跟被攻击银行相邻或者间接相邻(距离<=2)的银行能量+1,除了第一次外,攻击一家银行需要满足以下条件:
①:跟被攻击过后的银行相邻;
②:能量低于攻击者
③:银行没有被攻击过
题解:可以从题意得知,比如攻击银行i,如果说银行i能量为t,跟银行距离>=2的银行中能量最大的为mx,自身至少所需能量=max(t+1,mx+2),因为其他银行能量最多也只能+2;
这样,我们只需要遍历1~n家银行找到最少需要的能量就可以了;
这里我们用了两个c++数据结构,vector和multiset。vector属于<vector>是动态数组,multiset属于<set>会自动将里面的数字按从小到大排好;
1 #include<iostream> 2 #include<cstdio> 3 #include<set> 4 #include<vector> 5 using namespace std; 6 const int N=3e5+5; 7 vector<int>v[N]; 8 multiset<int>ms; 9 10 int main(){ 11 int n,a,b; 12 int arr[N]; 13 scanf("%d",&n); 14 for(int i=1;i<=n;i++){ 15 scanf("%d",arr+i); 16 ms.insert(arr[i]); 17 } 18 for(int i=1;i<=n-1;i++){ 19 scanf("%d %d",&a,&b); 20 v[a].push_back(b); 21 v[b].push_back(a); 22 } 23 int ans=1<<30; 24 multiset<int>::iterator it; 25 for(int i=1;i<=n;i++){//遍历n家银行,找到需要最少能量的银行 26 //存下银行i的值后,在ms中删除 27 int temp=arr[i]; 28 ms.erase(ms.find(arr[i])); 29 //找到跟i相邻的银行,比较后,在ms中删除 30 for(int j=0;j<v[i].size();j++){ 31 int k=v[i][j]; 32 temp=max(temp,arr[k]+1); 33 ms.erase(ms.find(arr[k])); 34 } 35 //比较距离大于2的银行能量最大值+2和temp的大小,保证每个银行都可以攻击 36 if(!ms.empty()){ 37 it=ms.end(); 38 temp=max(temp,*(--it)+2);//由于ms.end()指向最后一位,而不是最后一个元素所以--it; 39 } 40 //还原ms中删除的元素 41 ms.insert(arr[i]); 42 for(int j=0;j<v[i].size();j++){ 43 int k=v[i][j]; 44 ms.insert(arr[k]); 45 } 46 ans=min(temp,ans);//找到所有情况中最少的能量 47 } 48 printf("%d\n",ans); 49 }
另外附上一种贪心写法:
C1为mx个数 C2为mx-1个数
ans=mx 只有当C1=1&&正好有C2个mx-1与mx相连
ans=mx+1 只有当存在一个点满足 其距离<=1内 mx的个数为C1
其余情况ans=mx+2
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef pair<ll,ll> ii; 5 const ll inf=1e10; 6 const int N=2e6+20; 7 ll n,a[N],vis[N],can[N]; 8 vector<int> e[N]; 9 void solve() 10 { 11 ll C1=0,C2=0,mx=-inf,u; 12 for(int i=1;i<=n;i++) 13 mx=max(a[i],mx); 14 for(int i=1;i<=n;i++) 15 { 16 if(a[i]==mx) 17 C1++,u=i; 18 else if(a[i]==mx-1) 19 C2++; 20 } 21 ll ans=inf; 22 if(C1==1)// 23 { 24 int cnt=0; 25 for(int i=0;i<e[u].size();i++) 26 { 27 int v=e[u][i]; 28 if(a[v]==mx-1) 29 cnt++; 30 } 31 if(cnt==C2) 32 ans=mx; 33 } 34 if(ans==inf) 35 { 36 for(int i=1;i<=n&&ans==inf;i++)//遍历边O(n),找到相邻为1内,有C1个mx 37 { 38 ll res=0; 39 if(a[i]==mx) 40 res++; 41 for(int j=0;j<e[i].size();j++) 42 { 43 int v=e[i][j]; 44 if(a[v]==mx) 45 res++; 46 } 47 if(res==C1) 48 ans=mx+1; 49 } 50 } 51 if(ans==inf) 52 ans=mx+2; 53 cout<<ans<<endl; 54 } 55 int main() 56 { 57 while(cin>>n) 58 { 59 for(int i=1;i<=n;i++) 60 scanf("%I64d",&a[i]),e[i].clear(); 61 int u,v; 62 for(int i=1;i<=n-1;i++) 63 { 64 scanf("%d%d",&u,&v); 65 e[u].push_back(v); 66 e[v].push_back(u); 67 } 68 solve(); 69 } 70 return 0; 71 }
Codeforces Codeforces Round #408 (Div. 2) Bank Hacking(数据结构)
原文:http://www.cnblogs.com/fu3638/p/6696994.html