牛客刷题-Day39
今日刷题:\(1023-1026\)
1023 NC16466 [NOIP2015]信息传递
题目描述
有 \(n\) 个同学(编号为 \(1\) 到 \(n\))正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为 \(i\) 的同学的信息传递对象是编号为 \(T_i\) 的同学。
游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息, 但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?
输入描述
第 \(1\) 行包含 \(1\) 个正整数 \(n\),表示 \(n\) 个人。
第 \(2\) 行包含 \(n\) 个用空格隔开的正整数 \(T_1,T_2, … … ,T_n\),其中第 \(i\) 个整数 \(T_i\) 表示编号为 \(i\) 的同学的信息传递对象是编号为 \(T_i\) 的同学,\(T_i≤ n\) 且 \(T_i≠ i\)。
数据保证游戏一定会结束。
输出描述
\(1\) 个整数,表示游戏一共可以进行多少轮。
示例
输入
5
2 4 2 3 1
输出
3
说明
游戏的流程如图所示。当进行完第 \(3\) 轮游戏后,\(4\) 号玩家会听到 \(2\) 号玩家告诉他自己的生日,所以答案为 \(3\)。当然,第 \(3\) 轮游戏后,\(2\) 号玩家、\(3\) 号玩家都能从自己的消息来源得知自己的生日,同样符合游戏结束的条件。
备注
对于 \(30\%\) 的数据,\(n≤ 200\);
对于 \(60\%\) 的数据,\(n≤ 2500\);
对于 \(100\%\) 的数据,\(n≤ 200000\)。
解题思路
找出所有的环,并求出最短的环。
将所有入度为零的点加入队列,然后遍历这些点,依次删除其相邻的边,其相邻的点的入度减一,将新的入度为零的点加入队列。最后剩下来的入度非零的点即在环上的点。
在剩下的点进行深搜确定环的长度。
C++ 代码
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
int n, a[N], d[N], st[N]; // d[i] 表示 i 的入度
int ans = N;
void dfs(int root, int cur, int cnt) {
if (root == cur && cnt) {
ans = min(ans, cnt);
return;
}
if (!st[a[cur]]) {
st[a[cur]] = true;
dfs(root, a[cur], cnt + 1);
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
d[a[i]]++;
}
queue<int> q;
for (int i = 1; i <= n; i++) {
if (!d[i])
q.push(i);
}
while (q.size()) {
auto t = q.front();
q.pop();
d[a[t]]--;
// cout << a[t] << ' ' << d[a[t]] << endl;
if (!d[a[t]])
q.push(a[t]);
}
for (int i = 1; i <= n; i++)
if (d[i])
dfs(i, i, 0);
cout << ans << endl;
return 0;
}
1024 NC25064 [USACO 2007 Mar G]Ranking the Cows
题目描述
Each of Farmer John's \(N\) cows (\(1 ≤ N ≤ 1,000\)) produces milk at a different positive rate, and FJ would like to order his cows according to these rates from the fastest milk producer to the slowest.
FJ has already compared the milk output rate for \(M\) (\(1 ≤ M ≤ 10,000\)) pairs of cows. He wants to make a list of \(C\) additional pairs of cows such that, if he now compares those \(C\) pairs, he will definitely be able to deduce the correct ordering of all \(N\) cows. Please help him determine the minimum value of \(C\) for which such a list is possible.
输入描述
Line \(1\): Two space-separated integers: \(N\) and \(M\)
Lines \(2..M+1\): Two space-separated integers, respectively: \(X\) and \(Y\). Both \(X\) and \(Y\) are in the range \(1...N\) and describe a comparison where cow \(X\) was ranked higher than cow \(Y\).
输出描述
Line \(1\): A single integer that is the minimum value of \(C\).
示例
输入
5 5
2 1
1 5
2 3
1 4
3 4
输出
3
说明
From the information in the \(5\) test results, Farmer John knows that since cow \(2\) > cow \(1\) > cow \(5\) and cow \(2\) > cow \(3\) > cow \(4\), cow \(2\) has the highest rank. However, he needs to know whether cow \(1\) > cow \(3\) to determine the cow with the second highest rank. Also, he will need one more question to determine the ordering between cow \(4\) and cow \(5\). After that, he will need to know if cow \(5\) > cow \(3\) if cow \(1\) has higher rank than cow \(3\). He will have to ask three questions in order to be sure he has the rankings: "Is cow \(1\) > cow \(3\)? Is cow \(4\) > cow \(5\)? Is cow \(5\) > cow \(3\)?"
解题思路
题目大意:有 \(n\) 头牛需要给他们排序,然后可以确定 \(m\) 个比较关系,问还需要多少比较关系可以确定所有的次序。
要确定 \(n\) 个点的次序,则需要 \(n*(n-1)/2\) 个比较关系,则根据目前的 \(m\) 个比较关系推理出每个点所大于的点,然后将每个点与其他点不确定的大小进行统计,与 \(n*(n-1)/2\) 相减。
如何推理?使用 \(Floyd\) 算法,如果 \(i>j\) 并且 \(j>k\),则 \(i>k\),带入算法相当于两点间存在一条有向边,确定是否可以通过算法连通。
这里使用 bitset 进行优化,bitset里的每一位都是 \(0\) 或者 \(1\),代码中的 \(reach[i]\) 相当于存储了 \(i\) 与其余点的连通关系。
\(reach[i][j]=reach[i][k]\, |\, reach[k][j]\),可简化为 \(reach[i]=reach[i]\, |\, reach[k]\),前提是 \(i\) 与 \(k\) 连通,即 \(i\) 能到 \(k\),则 \(i\) 能到 \(k\) 能到的所有点。
C++ 代码
// NC25064 [USACO 2007 Mar G]Ranking the Cows
#include <bits/stdc++.h>
using namespace std;
const int N = 1015;
int n, m;
bitset<N> reach[N]; // reach[i][j] = 1 表示 i > j
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i)
reach[i][i] = 1;
for (int i = 0; i < m; ++i) {
int u, v;
cin >> u >> v;
reach[u][v] = 1;
}
for (int k = 1; k <= n; ++k) {
for (int i = 1; i <= n; ++i) {
if (reach[i][k]) {
reach[i] |= reach[k];
}
}
}
int count = 0;
for (int i = 1; i <= n; ++i)
count += reach[i].count() - 1;
cout << n * (n - 1) / 2 - count << endl;
return 0;
}
1025 NC24948 [USACO 2008 Jan S]Cow Contest
题目描述
\(N\) (\(1 ≤ N ≤ 100\)) cows, conveniently numbered \(1..N\), are participating in a programming contest. As we all know, some cows code better than others. Each cow has a certain constant skill rating that is unique among the competitors.
The contest is conducted in several head-to-head rounds, each between two cows. If cow \(A\) has a greater skill level than cow \(B\) (\(1 ≤ A ≤ N; 1 ≤ B ≤ N; A ≠ B\)), then cow \(A\) will always beat cow \(B\).
Farmer John is trying to rank the cows by skill level. Given a list the results of \(M\) (\(1 ≤ M ≤ 4,500\)) two-cow rounds, determine the number of cows whose ranks can be precisely determined from the results. It is guaranteed that the results of the rounds will not be contradictory.
输入描述
- Line \(1\): Two space-separated integers: \(N\) and \(M\)
- Lines \(2..M+1\): Each line contains two space-separated integers that describe the competitors and results (the first integer, \(A\), is the winner) of a single round of competition: \(A\) and \(B\)
输出描述
- Line \(1\): A single integer representing the number of cows whose ranks can be determined
示例
输入
5 5
4 3
4 2
3 2
1 2
2 5
输出
2
说明
Cow \(2\) loses to cows \(1\), \(3\), and \(4\). Thus, cow \(2\) is no better than any of the cows \(1\), \(3\), and \(4\). Cow \(5\) loses to cow \(2\), so cow \(2\) is better than cow \(5\). Thus, cow \(2\) must be fourth, and cow \(5\) must be fifth. The ranks of the other cows cannot be determined.
解题思路
思路类似 \(1024\),即通过 \(Floyd\) 确定大小关系,假设 \(n\) 个点,如果一个点大于或者小于的点的总和为 \(n-1\),则该点的大小关系是确定的。
Java 代码
import java.util.Scanner;
public class Main {
private static final int N = 110;
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), m = sc.nextInt();
int[][] g = new int[N][N];
for (int i = 0; i < m; i++) {
int a = sc.nextInt(), b = sc.nextInt();
g[a][b] = 1;
}
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
g[i][j] |= g[i][k] & g[k][j];
int ans = 0;
for (int i = 1; i <= n; i++) {
int cnt = 0;
for (int j = 1; j <= n; j++)
if (i != j && (g[i][j] == 1 || g[j][i] == 1))
cnt++;
if (cnt == n - 1) ans++;
}
System.out.print(ans);
}
}
1026 NC16697 [NOIP2001]Car的旅行路线
题目描述
又到暑假了,住在城市 \(A\) 的 Car 想和朋友一起去城市 \(B\) 旅游。她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第 \(i\) 城市中高速铁路了的单位里程价格为 \(T_i\),任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为 \(t\)。

图例(从上而下)
机场
高速铁路
飞机航线
注意:图中并没有标出所有的铁路与航线。
那么 Car 应如何安排到城市 \(B\) 的路线才能尽可能的节省花费呢?她发现这并不是一个简单的问题,于是她来向你请教。
任务:找出一条从城市 \(A\) 到 \(B\) 的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。
输入描述
第一行为一个正整数 \(n\)($ 0 ≤ n ≤ 10$ ),表示有 \(n\) 组测试数据。
每组的第一行有 \(4\) 个正整数 \(S,t,A,B\)。
\(S\)( \(0 < S ≤ 100\) )表示城市的个数,\(t\) 表示飞机单位里程的价格,\(A\),\(B\) 分别为城市 \(A\),\(B\) 的序号,( \(1 ≤ A\),\(B ≤ S\) )。
接下来有 \(S\) 行,其中第 \(i\) 行均有 \(7\) 个正整数 \(x_i1,y_i1,x_i2,y_i2,x_i3,y_i3,T_i\) 这当中的(\(x_i1,y_i1\)),(\(x_i2,y_i2\)),(\(x_i3,y_i3\))分别是第 \(i\) 个城市中任意 \(3\) 个机场的坐标,\(T_i\) 为第 \(i\) 个城市高速铁路单位里程的价格。
输出描述
共有 \(n\) 行,每行 \(1\) 个数据对应测试数据(最小花费)。保留一位小数。
示例
输入
1
3 10 1 3
1 1 1 3 3 1 30
2 5 7 4 5 2 1
8 6 8 8 11 6 3
输出
47.5
解题思路
思路不难,求最短路,使用 Dijkstra 算法即可。
建图需要注意:给出的机场是任意三个点,第四个点需要根据三个点的位置确定对角线上的两个点然后使用中点坐标求解第四个点。此外,需要将机场也抽象成一个点,最初可以在 \(A\) 的任一个机场出发,因此起始点有四个,当是不同城市的机场时,边的单位权重是不同的。
C++ 代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
#define PII pair<double, int>
int S, T, A, B, idx = 1, Tr[N]; //Tr[i] 存放第 i 个城市内的道路费
struct ap {
double x, y;
int city, pos;
} aps[N << 2];
vector<ap> city[N];
// 添加城市内机场节点
void add(int i, double x1, double x2, double x3,
double y1, double y2, double y3) {
city[i].push_back({x1, y1, i, idx});
aps[idx] = {x1, y1, i, idx}; idx++;
city[i].push_back({x2, y2, i, idx});
aps[idx] = {x2, y2, i, idx}; idx++;
city[i].push_back({x3, y3, i, idx});
aps[idx] = {x3, y3, i, idx}; idx++;
double l1, l2, l3, maxl;
l1 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
l2 = (x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2);
l3 = (x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3);
maxl = max(max(l1, l2), l3);
if (l1 == maxl) {
city[i].push_back({(x1 + x2 - x3), (y2 + y1 - y3), i, idx});
aps[idx] = {(x1 + x2 - x3), (y2 + y1 - y3), i, idx};
idx++;
} else if (l2 == maxl) {
city[i].push_back({(x2 + x3 - x1), (y2 + y3 - y1), i, idx});
aps[idx] = {(x2 + x3 - x1), (y2 + y3 - y1), i, idx};
idx++;
} else {
city[i].push_back({(x1 + x3 - x2), (y1 + y3 - y2), i, idx});
aps[idx] = {(x1 + x3 - x2), (y1 + y3 - y2), i, idx};
idx++;
}
}
// 计算边权
double calc(int a, int b){
double res = sqrt((aps[a].x - aps[b].x) * (aps[a].x - aps[b].x)
+ (aps[a].y - aps[b].y) * (aps[a].y - aps[b].y));
if (aps[a].city != aps[b].city) {
res *= T;
} else {
res *= Tr[aps[a].city]; // Tr[i] 存放第 i 个城市内的道路费
}
return res;
}
bool st[N << 2];
double dist[N << 2];
priority_queue<PII, vector<PII>, greater<PII>> q;
void dijkstra() {
for (ap i: city[A]) {
dist[i.pos] = 0;
q.push({0, i.pos});
}
while (q.size()) {
double dis;
int t;
PII cur = q.top();
dis = cur.first; t = cur.second;
q.pop();
if (st[t])
continue;
st[t] = 1;
for (int c = 1; c <= S; c++) {
for (ap j: city[c]) {
if (dist[j.pos] > calc(t, j.pos) + dis) {
dist[j.pos] = calc(t, j.pos) + dis;
q.push({dist[j.pos], j.pos});
}
}
}
}
double ans = 0x3f3f3f3f;
for(ap i: city[B]) {
ans = min(ans, dist[i.pos]);
}
printf("%.1f", ans);
}
void solve(){
idx = 1;
memset(st, 0, sizeof st);
for (int i = 1; i < (N << 2); i++) {
dist[i] = 0x3f3f3f3f;
}
cin >> S >> T >> A >> B;
for (int i = 1; i <= S; i++) {
double x1, x2, x3, y1, y2, y3;
cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> Tr[i];
city[i].clear();
add(i, x1, x2, x3, y1, y2, y3);
}
dijkstra();
}
int n;
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
solve();
}
return 0;
}
本文来自博客园,作者:Cocoicobird,转载请注明原文链接:https://www.cnblogs.com/Cocoicobird/p/19982427

浙公网安备 33010602011771号