8.19的牛客模拟赛
暑假里做了很多这种区域赛,但是还没有补题,最近会慢慢补完
传送门
A. Commemorative Race
题意
在一个有向无环图中,将其最长路的一条边删掉,然后再从这个起点开始,求所能达到的最长路径中的最小值。
题解
通过两次 d f s dfs dfs解决,首先建立一个“超级源点”,向所有的点连边
- 第一次 d f s dfs dfs,从“超级源点”开始,处理出以 i i i点为起点能够达到的最长路径和次长路径长度—— m a x l e n [ i ] maxlen[i] maxlen[i]和 m a x l e n 1 [ i ] maxlen1[i] maxlen1[i]
- 第二次 d f s dfs dfs,从“超级源点”开始,沿着最长路径走,并更新答案数组为 当前长度+以当前点为起点的次长路径长度
最后在ans数组中取最小值(注意只统计长度出现过一次的路径,原因还没想明白,留个坑)
代码
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100005;
const int MAXM = 2e6+99;
int num_edge,n,m,x,y,maxlen[MAXN],maxlen2[MAXN], head[MAXN];
struct Edge{
int next, to;
}edge[MAXM];
bool vis[MAXN], b[MAXN];
int cnt[MAXN], ans[MAXN];
void add_edge(int from, int to)
{
edge[++num_edge].next = head[from];
edge[num_edge].to = to;
head[from] = num_edge;
}
int dfs(int x)
{
if (vis[x]) return maxlen[x];
vis[x] = 1;
int tmp = 0;
for (int i = head[x]; i; i = edge[i].next)
{
int to = edge[i].to;
tmp = dfs(to) + 1;
if (tmp > maxlen[x])
{
maxlen2[x] = maxlen[x];
maxlen[x] = tmp;
}
else if (tmp > maxlen2[x])
maxlen2[x] = tmp;
}
return maxlen[x];
}
void dfs2(int x, int len)
{
if (b[x]) return;
b[x] = 1;
for (int i = head[x]; i; i = edge[i].next)
{
int to = edge[i].to;
if (maxlen[x] == maxlen[to] + 1)
{
dfs2(to, len + 1);
cnt[len] ++;
ans[len] = len + maxlen2[x];
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; i ++) add_edge(0,i);
for (int i = 1; i <= m; i ++)
{
scanf("%d%d",&x,&y);
add_edge(x,y);
}
dfs(0);
dfs2(0,0);
int minn = maxlen[0];
for (int i = 1; i <= n; i ++)
if (cnt[i] == 1)
minn = min(minn, ans[i]);
printf("%d",minn - 1);
return 0;
}
B. Convoy
题意
有n个人和k辆车,每辆车上最多坐5个人,每个人都可以驾驶该车辆,并且其驾驶时间不同,问最少多长时间可以把这n个人从网目的地(司机可以回来拉人)
题解
尝试用贪心,当然是让驾驶速度最快的司机一直跑,其总时间等于最慢的那个司机的时间,但是这个过程并不好模拟。
于是就想到了二分,二分一个时间,看看能不能在规定时间内把人们都送到目的地。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <cmath>
using namespace std;
#define ll long long
int n, k;
ll a[50000];
bool judge(ll t)
{
ll ans = 0;
for (int i = 1; i <= k; i ++)
{
if (a[i