Brexit Negotiations(拓扑排序+反向建图)
作者:互联网
题目
题意: 需要开n个会议,一些特定会议开始之前需要先完成别的特定会议,并且在开始之前需要花k分钟总结先前完成的k场会议,每场会议都有原本需要的时长ei。求单场耗时最长的会议的最小值。
不妨设p = ei + k, 想要让 p 尽可能的小, 就要让k尽可能的小的同时, 让ei尽可能的大,也就是说当前若有多个可选择的值时,先选择权值大的.但这样会有一个问题, 这样选只能保证当目前来说是最优解,但是不能保证全局最优,因为我们不知道之后是不是会有比当前更大的ei,比如:
3
1000 1 2
1 0
999 0
若按之前的想法的话,一开始在1和999中选大的,选了999,最大值变成999,然后选1, 更新为1 + 1 = 2, 最后选择1000, 更新为1000 + 2 = 1002.
我们可以发现,这并不是最优解,因为我们可以先选1,然后选1000,得到1000 + 1 = 1,然后再选999,得到999 + 2 = 1001, 最后答案为1001.
那我们不妨想想看, 若从最后选的会议开始往前看,p要怎么样才能最小.其实只要让最后选的ei尽可能小的同时, k尽可能大就可以,也就是先选ei小的.而且逆向来看的话,k是会越来越小的,这样实际上也满足了在ei越大的时候k越小,所以逆向贪心一定是最优解.所以将拓扑排序反向建边之后,每次选ei最小的点更新最大值就可以.
#include <bits/stdc++.h>
#define PII pair<int, int>
#define IOS std::ios::sync_with_stdio(false);std::cin.tie(0)
using namespace std;
const int N = 4e5 + 100;
int h[N], e[N], ne[N], idx, d[N], w[N];
long long res = -1;
int n;
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++;
}
void topsort()
{
priority_queue<PII,vector<PII>, greater<PII> > Q;
long long ans = n;
for(int i = 1; i <= n; i ++)
if(d[i] == 0) Q.push({w[i], i});
while(!Q.empty())
{
auto head = Q.top();
Q.pop();
ans --; //每次完成的会议数-1
int now = head.second;
int v = head.first;
res = max(res, v + ans);
for(int j = h[now]; ~j; j = ne[j])
{
int to = e[j];
d[to] --;
if(d[to] == 0)
Q.push({w[to], to});
}
}
}
int main()
{
IOS;
memset(h, -1, sizeof h);
cin >> n;
for(int i = 1; i <= n; i ++)
{
int x, y;
cin >> w[i] >> x;
while(x --)
{
cin >> y;
add(i, y); //反向连边
d[y] ++; //记录入度
}
}
topsort();
cout << res;
return 0;
}
/*
6
2 2 4 3
4 1 5
1 2 2 4
3 1 5
2 0
4 1 3
*/
标签:Brexit,ei,idx,int,999,long,建图,Negotiations,1000 来源: https://blog.csdn.net/weixin_45925735/article/details/113474036