题目链接
解题思路:
我们首先将奶牛可以承受的最小值,递减排序,也就是降序排列,然后将防晒霜固定的值,递减排序,还是降序排列.
对于每一个头奶牛而言,当然是要选择目前来说满足条件的最差的防晒霜,什么最差的定义,就是选择满足奶牛条件的SPF最大的那一瓶防晒霜.
注意:降序排序,保证对于每一头牛而言,它用的是,可以使用的最差的防晒霜,因为值越小的防晒霜,有可能让更多的牛使用.而升序排列,就恰好反了. 注意:如果一头牛没有合适的防嗮霜给它了就不用管他了。
拓展知识点:
增广路径:
预先选一些匹配的边,从任一个不在匹配的点,先沿着非匹配边,再沿着匹配边走,。。。,交替,最后找到一个不在匹配里的点。(就找到了一个增广路径)。 如果一个匹配没有增广路径,则达到了最大匹配。
代码:
#include<stdio.h> #include<map> #include<algorithm> using namespace std; typedef pair<int ,int > pll; const int N = 2510; int n ,m; pll cows[N]; int main(){ scanf("%d%d",&n,&m); for(int i=0;i<n;++i)scanf("%d%d",&cows[i].first,&cows[i].second); sort(cows,cows+n); map<int,int >spfs; for(int i=0;i<m;++i){ int x,cover; scanf("%d%d",&x,&cover); spfs[x] += cover; } int ans = 0; spfs[0] = spfs[1001] = n; // 哨兵,避免使用 查找函数时出错 for(int i = n-1;i >= 0;--i){ auto cow = cows[i]; // 大于的最小的值 auto it = spfs.upper_bound(cow.second); // 以区间的右边找 ,难点一 it--; // 找到小于等于的最大值 if(it->first >= cow.first && it->first <= cow.second){ ans ++; if(-- it->second == 0) spfs.erase(it); // 难点二 } } printf("%d\n",ans); return 0; }
题目链接
解题思路:
pair<pair<int,int>,int>
的方式来存储。代码:
#include<stdio.h> #include<vector> #include<algorithm> #include<queue> using namespace std; typedef pair<int ,int> PII ; pair <PII,int> cows[50010]; int n; int id[50010]; int main (){ scanf("%d",&n); for(int i = 0;i<n;++i){ // 难点一就是如何存这么多元素 scanf("%d%d",&cows[i].first.first,&cows[i].first.second); cows[i].second = i; } sort(cows,cows+n); priority_queue<PII,vector<PII>,greater<PII>>heap; for(int i=0;i<n;++i){ auto cow = cows[i].first; // 新建一个围栏 if(heap.empty() || heap.top().first >= cow.first){ PII stall = {cow.second ,heap.size() + 1 }; id[cows[i].second] = stall.second; heap.push(stall); }else{ // 难点二,更新围栏 PII stall = heap.top(); heap.pop(); stall.first = cow.second; id[cows[i].second] = stall.second; heap.push(stall); } } printf("%d\n",heap.size()); for(int i = 0;i <n ;++i) printf("%d\n",id[i]); return 0; }
题目链接
解题思路
如下图所示,对于任意一个小岛 (x,y)(x,y),我们都可以在海岸线上求出能覆盖该小岛的建造雷达的区间 [a,b]。
由勾股定理,将所有小岛转化成区间后,问题转化为:给定 n 个区间,在 x轴上选择尽量少的点,使得所有区间至少包含一个点。
算法步骤:
代码:
#include<stdio.h> #include<algorithm> #include<math.h> using namespace std; typedef pair<double,double> PDD; const double eps = 1e-6 , INF = 1e10; int n,R; PDD segs[1010]; bool success ; int main(){ success = 1; scanf("%d%d",&n,&R); for(int i = 0;i< n;++i){ int x,y; scanf("%d%d",&x,&y); if(y > R){ success = 0; break; } double len = sqrt(R * R - y * y ); segs[i] = {x + len,x - len}; } if(!success) puts("-1"); else{ sort(segs,segs + n); int ans = 0; double pos = - INF; for(int i = 0;i<n;++i){ auto seg = segs[i]; if(seg.second - pos > eps){ ans ++ ; pos = seg.first; } } printf("%d\n",ans); } return 0; }
题目链接
解题思路
每次找出当前权值最大的非根节点,将其染色顺序排在紧随父节点之后的位置,然后将该点合并进父节点中,更新父节点的权值。直到将所有点都合并进根节点为止。
如果直接按上述算法做的话,最终的分值不太容易计算,我们可以在将点合并的时候,实时更新当前的权值和:
难点:
因此可以看到只要将父节点的关系转化以下就好。
我们看把 y 的一堆节点放到x 后边 ,x 的值是不会变得,而 y 每一个节点的值相当于 乘上 x 中 的节点个数。
代码:
#include<stdio.h> #include<algorithm> using namespace std; const int N = 1010; struct node{ int father,size,sum; double avg; }nodes[N]; int n ,root; // 根据 平均值,找到最大的点 int find(){ int pos = -1 ; double maxx = 0; for(int i= 1;i <= n ;++i){ if( i != root && maxx < nodes[i].avg){ maxx = nodes[i].avg; pos = i; } } return pos; } int main(){ int ans = 0; scanf("%d%d",&n,&root); for(int i = 1;i <=n; ++i) { node &nd = nodes[i]; scanf("%d",&nd.sum); nd.size = 1 ; nd.avg = nd.sum; ans += nd.sum; // } // 建立关系 for(int i = 0, a, b;i< n-1;++i ){ scanf("%d%d",&a,&b); nodes[b].father = a; } // 遍历 n - 1 次 for(int i = 0;i< n -1; ++ i){ int ver = find(); int fa = nodes[ver].father; // 当前节点的 总和 乘上 父节点 的大小 ans += nodes[ver].sum * nodes[fa].size; // 用完这后将该节点删除, //因为 找节点是用find () 函数 依据avg 值找,所以置为 -1 就不会用到了 nodes[ver].avg = -1; // 难点 :合并节点,遍历所有节点。 // 将原本是其 子节点 的直接连上其父节点即可 for(int j = 1 ; j <= n ;++j) if(nodes[j].father == ver) nodes[j].father = fa; // 难点三 : 更新父节点的信息 nodes[fa].size += nodes[ver].size ; nodes[fa].sum += nodes[ver].sum; nodes[fa].avg = (double)nodes[fa].sum / nodes[fa].size; } printf("%d\n",ans); return 0; }
写在最后,感谢y总的讲解。