B 直线
#include<iostream>
#include<vector>
#include<set>
#include<cmath>
#include<climits>
using namespace std;
struct Point{
int x, y;
Point(int a, int b):x(a),y(b){}
};
struct Line{
double k, b;
Line(double x, double y):k(x),b(y){}
// Line& operator = (const Line& li){
// if(abs(k - li.k) < 1e-6 && abs(b - li.b) < 1e-6)
// return *this;
// }
friend bool operator<(const Line & x,const Line & y)
{
if(x.k < y.k)return true;
if(abs(x.k - y.k) < 1e-6){
return x.b < y.b;
}
}
};
int main()
{
vector<Point> p;
set<Line> kb;
for(int i = 0; i < 20; i++){
for(int j = 0; j < 21; j++){
Point a(i, j);
p.push_back(a);
}
}
int l = p.size();
for(int i = 0; i < l - 1; i++){
for(int j = i + 1; j < l;j++){
double k = 0, b = 0;
if(p[i].x - p[j].x != 0 && p[i].y - p[j].y != 0){
k = 1.0* (p[i].y - p[j].y) / (p[i].x - p[j].x);
b = p[i].y - k * p[i].x;
}
else if(p[i].y - p[j].y == 0){
k = 0;
b = p[i].y;
}
else{
k = INT_MAX;
b = p[i].x;
}
Line li(k, b);
//kb.insert(li);
if(kb.count(li) == 0){
kb.insert(li);
//cout << "√" << endl;
}
// cout << "dian:" << p[i].x << ' ' << p[i].y << ' ';
// cout << "dian:" << p[j].x << ' ' << p[j].y << endl;
// cout << k << ' ' << b << endl << endl;
}
}
cout << kb.size();
return 0;
}
D 路径
答案:10266837
1.用了Dijkstra 算法,因为只求最短路径长度,下面的path数组可以不用
#include<iostream>
#include<climits>
using namespace std;
int g[2025][2025]; //图
bool f[2025]; //标记各顶点是否找到最短路径
int dist[2025]; //最短路径长度
int path[2025]; //路径上的前驱结点
int imax = INT_MAX;
int gcd(int a, int b){ //a >= b
int c = b;
while(a % b != 0){
c = a % b; a = b; b = c;
}
return c;
}
int bei(int a, int b){ //a >= b
int c = gcd(a, b);
return a / c * b;
}
int main()
{
//初始化图
for(int i = 1; i <= 2021; ++i){
g[i][i] = imax;
for(int j = i + 1; j <= 2021; ++j){
if(j - i <= 21){
g[i][j] = bei(j, i); g[j][i] = g[i][j];
}
else{
g[i][j] = imax; g[j][i] = imax;
}
}
}
//初始化功能数组
f[1] = true; dist[1] = 0; path[1] = -1;
for(int i = 2; i <= 2021; i++){
f[i] = false; dist[i] = g[1][i]; path[i] = (g[1][i] == imax) ? -1 : 0;
}
int k = 2020;
while(k){
k--;
//找到还没确定最短路径,且dist最小的点Vt,标记其为找到最小路径
int mind = imax; int t;
for(int i = 2; i <= 2021; i++){
if(f[i] == false && dist[i] < mind){
t = i;
mind =dist[i];
}
}
f[t] = true;
//对于邻接自Vt的结点Vj,更新最短路径
for(int j = 2; j <= 2021; j++){
if(g[t][j] != imax && f[j] == false && dist[t] + g[t][j] < dist[j]){
dist[j] = dist[t] + g[t][j];
path[j] = t;
}
}
}
cout << dist[2021];
return 0;
}
2.Bellon-Ford算法
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
const int inf=0x3f3f3f3f;
const int maxn=1e5+5;
const int N=6e6+5;
const LL mod=998244353;
const double pi=acos(-1);
int gcd(int a,int b){
if(b==0) return a;
return gcd(b,a%b);
}
struct node{
int u,v,w;
node(int uu,int vv,int ww) { u=uu,v=vv,w=ww; }
};
int n,dis[maxn];
vector<node>g;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) dis[i]=inf; dis[1]=0;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
if(j-i>21) continue;
g.push_back( node( i , j , i*j/gcd(i,j) ) );
}
for(int i=1;i<=n-1;i++)
{
bool f=0; //在某次循环不再进行松弛时,直接退出循环
for(int j=0;j<g.size();j++)
{
int u=g[j].u,v=g[j].v,w=g[j].w;
if(dis[v]>dis[u]+w)
f=1,dis[v]=dis[u]+w;
}
if(f==0) break;
}
printf("%d\n",dis[n]);
return 0;
}
H 左孩子右兄弟
思路:建树,深搜
#include<bits/stdc++.h>
using namespace std;
//dfs,每次都取底层最大的,把这一层的每一个子结点都放最后取最大值+下面一层的层数
vector<int> node[100005]; //储存i的子结点
int high[100005];
int ans;
void dfs(){
stack<int> st;
st.push(1);
while(!st.empty()){
int top = st.top();
st.pop();
int len = node[top].size();
for(int i = 0; i < len; i++){
int child = node[top][i];
st.push(child);
high[child] = high[top] + len; //把每一个子结点放最后
ans = max(ans, high[child]);
}
}
}
int main()
{
int n, fa;
cin >> n;
for(int i = 2; i <= n; i++){
cin >> fa;
node[fa].push_back(i);
}
dfs(); //注意根节点高度为0
cout << ans;
return 0;
}
参考:https://blog.csdn.net/qq_45856614/article/details/115827861