码迷,mamicode.com
首页 > 其他好文 > 详细

友谊赛

时间:2016-07-20 22:56:36      阅读:239      评论:0      收藏:0      [点我收藏+]

标签:

题目:

【问题描述】

      大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】          【输入输出样例2】

friendly.in

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

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

friendly.out

3

3

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个字符。

不得不说,这道题有些丧病。。。考试时想了许久,最后暴力只过了20分QAQ。正解也是相当繁杂,先用kruskal来算最小生成树,之后用倍增求出两点到他们最近公共祖先的路径长度,取二者较大值即为答案。下面贴出代码(长的没有底哦):

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <string>
#include <algorithm>
using namespace std;
FILE *fin=fopen("friendly.in","r"),*fout=fopen("friendly.out","w");
long n,m,qn;
struct pat{long x,y,s;} a[100005];
bool operator <(pat a,pat b){
    return a.s<b.s;
}
long mb,mc,bh[100005],h[100005];
struct pat2{long lh,to,s,h;} b[200005];
void newb(long x,long y,long s){
    mb++; b[mb].to=y; b[mb].s=s; b[mb].lh=bh[x]; bh[x]=mb;
    mb++; b[mb].to=x; b[mb].s=s; b[mb].lh=bh[y]; bh[y]=mb;
}
map<string,long> M;
struct xxx{long s,h;} d[100005][20];
struct UFS{
    long n,fa[1000005];
    void init(long nn){
        n=nn;
        for (long i=0;i<nn;i++) fa[i]=i;
    }
    long root(long p){
        if (fa[p]!=p) fa[p]=root(fa[p]);
        return fa[p];
    }
    void uni(long x,long y){
        fa[root(x)]=root(y);
    }
}U;
inline void rut(string &s,char cc){
    char c;
    s="";
    for(fscanf(fin,"%c",&c);c!=cc&&!feof(fin);fscanf(fin,"%c",&c)) s+=c;
}
void init(){
    long i;
    string s;
    fscanf(fin,"%ld%ld\n",&n,&m);
    M.clear();
    for (i=0;i<n;i++){
        rut(s,\n);
        M[s]=i;
        //cout<<s<<endl;
    }
    for (i=0;i<m;i++){
        rut(s, ); a[i].x=M[s]; //cout<<s<<endl;
        rut(s, ); a[i].y=M[s]; //cout<<s<<endl;
        fscanf(fin,"%ld\n",&(a[i].s)); //cout<<a[i].s<<endl;
        //cout<<a[i].x<<‘ ‘<<a[i].y<<‘ ‘<<a[i].s<<endl;
    }
    mb=0;
    for (i=0;i<n;i++) bh[i]=0;
}
void Kruskal(){
    sort(a,a+m);
    U.init(n);
    for (long i=0;i<m;i++)
        if (U.root(a[i].x)!=U.root(a[i].y)){
            U.uni(a[i].x,a[i].y);
            newb(a[i].x,a[i].y,a[i].s);
            cout<<a[i].x<< <<a[i].y<< <<a[i].s<<endl;
        }
}
void dinit(){
    long i,t,k,p=0,q=1,Q[100005],P;
    bool f[100005];
    memset(f,0,sizeof(f));
    d[0][0].s=0; d[0][0].h=-1;
    h[0]=0; f[0]=1; Q[0]=0;
    while (p<q){
        P=Q[p];
        for (i=bh[P];i>0;i=b[i].lh){
            t=b[i].to;
            if (!f[t]){
                f[t]=1;
                Q[q++]=t;
                d[t][0].s=b[i].s;
                d[t][0].h=P;
                h[t]=h[P]+1;
            }
        }
        p++;
    }
    for (k=1;k<20;k++)
        for (i=0;i<n;i++){
            t=d[i][k-1].h;
            if (t>-1){
                d[i][k].h=d[t][k-1].h;
                d[i][k].s=max(d[i][k-1].s,d[t][k-1].s);
            }else d[i][k].h=-1;
        }
}
void tr(){
    long i,j,k,p,q,pp,qq,ans;
    string s;
    fscanf(fin,"%ld\n",&qn);
    for (i=0;i<qn;i++){
        rut(s, ); p=M[s]; //cout<<s<<endl;
        rut(s,\n); q=M[s]; //cout<<s<<endl;
        //cout<<p<<‘ ‘<<q<<endl;
        ans=0;
        if (h[p]<h[q]) {k=p;p=q;q=k;}
        for (j=0,k=h[p]-h[q];k>0;j++,k>>=1)
            if (k%2==1){
                if (ans<d[p][j].s) ans=d[p][j].s;
                p=d[p][j].h;
            }
        //cout<<h[p]<<‘ ‘<<h[q]<<endl;
        if (p==q){
            fprintf(fout,"%ld\n",ans);
            continue;
        }
        pp=p; qq=q;
        for (j=19;j>=0;j--)
            if (d[pp][j].h>-1){
                if (d[pp][j].h==d[qq][j].h)
                    k=d[pp][j].h;
                else{
                    pp=d[pp][j].h;
                    qq=d[qq][j].h;
                }
            }
        for (j=0,k=h[p]-h[k];k>0;j++,k>>=1)
            if (k%2==1){
                if (ans<d[p][j].s) ans=d[p][j].s;
                if (ans<d[q][j].s) ans=d[q][j].s;
                p=d[p][j].h;
                q=d[q][j].h;
            }
        fprintf(fout,"%ld\n",ans);
    }
}
int main(){
    init();
    Kruskal();
    dinit();
    tr();
    fclose(fin);
    fclose(fout);
    return 0;
}

清清正正射命丸文是也~

友谊赛

标签:

原文地址:http://www.cnblogs.com/Ayateriteri/p/5689710.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!