NOIP 模拟题 friendly [最小生成树] [ST在线] [hash]

本文介绍了一种模拟足球友谊赛中球员传球失误系数的方法。利用最小生成树与ST倍增算法,解决教练如何得知任意两名球员间传球可能达到的最小失误系数的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

友谊赛
(friendly.pas/.c/.cpp)
【问题描述】
大COS所在的FC幽寂即将与皇家钨冀进行一场足球友谊赛。与一般的足球比赛11人制不同,这场友谊赛两队各有n位球员同时在场上奔跑,场面十分壮(hun)观(luan)。当然,球还是只有一个。
现在,FC幽寂主教练卡犇要制定战术。在进攻上,为了保证团队的协调有序,(直接)传球必须在特定球员之间进行,方向不限。例如门将只会与最近的几个后卫传球。
受到个人能力和球员间默契的影响,可直接传球的两个球员之间有一个特定的失误系数,越大则表示越容易失误。不可直接传球的两个球员之间想要进行球的传递,则需通过其他球员来间接传球(战术已保证一个球员能直接或间接传给其他任意球员)。可直接传球球员之间也可以间接传球。根据木桶原理,间接传球的失误系数等于传球路线中所有直接传球的最大的失误系数。
在制定高级战术过程中,卡犇需要知道两名球员间传球(包括直接和间接)可能达到的最小的失误系数是多少。然而由于球员太多……
【输入】
输入文件名为friendly.in。
第一行两个正整数n、m,分别表示FC幽寂队场上球员数和可直接传球的球员有多少对。
接下来n行,每行一个字符串,分别表示每位球员姓名。
接下来m行,每行两个字符串s1、s2和一个正整数k,之间用一空格隔开,表示名为s1和名为s2的两个球员可以直接传球,失误系数为k。
第n+m+2行一个正整数q,表示卡犇的询问数。
接下来q行,每行两个字符串s1、s2,表示卡犇想知道名为s1和名为s2的两个球员之间传球可达的最小失误系数。
数据没有多余的空格和回车。
【输出】
输出文件名为friendly.out。
共q行,每行一个正整数,依次表示每个询问的答案。
【输入输出样例1】
friendly.in
6 8
KCN
COS
HOCN
CH4
HCOOH
CH3COOH
KCN COS 2
KCN HOCN 1
COS HOCN 4
COS CH4 5
HOCN HCOOH 3
CH4 HCOOH 2
CH4 CH3COOH 2
CH3COOH HCOOH 1
2
KCN CH3COOH
COS CH4
friendly.out
3
3
【输入输出样例2】
friendly.in
11 21
Neuer
LiYi
JJRoger
Xujiale
Shaqima
Gundogan
CRonaldo
Naldo
Mkhitaryan
Messi
GoalKeeper
Neuer LiYi 101
Neuer Xujiale 4
Neuer JJRoger 7
LiYi JJRoger 100
LiYi Shaqima 99
JJRoger Xujiale 10
JJRoger Shaqima 11
JJRoger Gundogan 6
Xujiale Gundogan 3
Xujiale CRonaldo 8
Xujiale Naldo 5
Gundogan Shaqima 10
Gundogan Naldo 6
Gundogan Mkhitaryan 9
Shaqima Mkhitaryan 21
Shaqima Messi 20
Naldo Mkhitaryan 10
Naldo GoalKeeper 9
Mkhitaryan GoalKeeper 9
CRonaldo Naldo 1
Messi Mkhitaryan 1
4
LiYi GoalKeeper
CRonaldo Messi
JJRoger Shaqima
Neuer GoalKeeper
friendly.out
99
9
10
9
【数据范围】
对于10%的数据,n≤100,m≤1,000,q≤100;
对于30%的数据,n≤1,000,m≤1,000,q≤1,000;
对于60%的数据,n≤1,000,m≤100,000,q≤100,000;
对于100%的数据,n≤100,000,m≤100,000,q≤100,000,失误系数≤100,000,000,球员名字互不相同且长度不超过10个字符。


使点对之间路径上的最大值最小
故求最小生成树
ST倍增算法维护最大边权值

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smin(x,tmp) x=min((x),(tmp))
#define smax(x,tmp) x=max((x),(tmp))
#define maxx(x,y,z) max(x,max(y,z))
#define minn(x,y,z) min(x,min(y,z))
const int INF=0x3f3f3f3f;
const int maxm = 100005;
const int maxn = 350005;
const unsigned int mod  = 349927;
const int maxd=25;
const int D = 20;
struct Hash
{
    char node[maxn][11];
    int next[maxn];
    int head[maxn];
    int maxnode;
    int insert(char s[])
    {
        int lens = strlen(s);
        int pos= 0;
        unsigned int hh = 0;
        while(pos < lens)
            hh = (hh<<5) ^ (hh>>27) ^ s[pos++];
        hh %= mod;
        int root = head[hh];
        while(~root)
        {
            if(strcmp(s,node[root]) == 0) return root;
            root = next[root];
        }
        strcpy(node[++maxnode],s);
        next[maxnode] = head[hh];
        head[hh] = maxnode;
        return maxnode;
    }
    void clear()
    {
        memset(head,-1,sizeof(head));
        maxnode = 0; // use the 1 at first
    }
}hash;
struct Road
{
    int u,v,c;
    bool operator < (const Road t) const { return c < t.c; }
}road[maxm];
char s[11];
int n,m;
int fa[maxn]; // set for node[]
int find(int x)
{
    if(x ^ fa[x]) fa[x] = find(fa[x]);
    return fa[x];
}
inline bool union_find(int x,int y)
{
    int t1 = find(x), t2 = find(y);
    if(t1 == t2) return false;
    fa[t2] = t1;
    return true;
}

struct Edge
{
    int to,next;
    int val;
}edge[maxm<<1];
int head[maxn];
int maxedge;
inline void addedge(int u,int v,int c)
{
    edge[++maxedge] = (Edge) { v,head[u],c };
    head[u] = maxedge;
    edge[++maxedge] = (Edge) { u,head[v],c };
    head[v] = maxedge;
}
void kruskal()
{
    sort(road+1,road+m+1);
    int tot = 0;
    for(int i=1;i<=m;i++)
    {
        if(union_find(road[i].u,road[i].v)) tot++ , addedge(road[i].u,road[i].v,road[i].c);
        if(tot >= n-1) break;
    }
}
int dp[maxn][maxd];
int f[maxn][maxd];
int depth[maxn];
int root;
inline void init()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) fa[i] = i;
    memset(head,-1,sizeof(head));
    maxedge = -1;
    memset(depth,0,sizeof(depth));
    hash.clear();
    for(int i=1;i<=n;i++) scanf("%s",s);
    root = hash.insert(s);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",s);
        road[i].u = hash.insert(s);
        scanf("%s",s);
        road[i].v = hash.insert(s);
        scanf("%d",&road[i].c);
    }
}
void dfs(int u,int dep)
{
    depth[u] = dep;
    for(int k=1;k<=D;k++) // ascending order!!!
    {
        f[u][k] = f[f[u][k-1]][k-1];
        dp[u][k] = max(dp[u][k-1],dp[f[u][k-1]][k-1]);
    }
    for(int i=head[u];~i;i=edge[i].next)
    {
        int v = edge[i].to;
        if(depth[v]) continue;
        dp[v][0] = edge[i].val;
        f[v][0] = u;
        dfs(v,dep+1);
    }
}
int Find(int u,int v)
{
    if(depth[u] < depth[v]) swap(u,v);
    int ans = 0;
    for(int k=D;k>=0;k--) if(depth[v] <= depth[f[u][k]])
    {
        smax(ans , dp[u][k]);
        u = f[u][k];
    }
    if(u == v) return ans;
    for(int k=D;k>=0;k--) if(f[u][k] ^ f[v][k])
    {
        smax(ans , dp[u][k]);
        smax(ans , dp[v][k]);
        u = f[u][k];
        v = f[v][k];
    }
    return maxx(ans,dp[u][0],dp[v][0]); // attention the f && the dp!!
}
int main()
{
    freopen("friendly.in","r",stdin);
    freopen("friendly.out","w",stdout);
    init();
    kruskal();
    dfs(root,1);
    int q;
    scanf("%d",&q);
    while(q--)
    {
        scanf("%s",s);
        int u = hash.insert(s);
        scanf("%s",s);
        int v = hash.insert(s);
        int ans = Find(u,v);
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值