pat(八)

1071——1080

1071[散列表]

Speech Patterns

思路:建立字典查询即可。

//
// @author prime on 2017/7/1.
//
#include <iostream>
#include <map>
#include <cctype>

using namespace std;

int main()
{
    string input,tmp;
    getline(cin,input);
    map<string,int> dict;
    for (int i=0;i<input.size();++i)
    {
        if(isalnum(input[i]))
        {
            input[i]=tolower(input[i]);
            tmp+=input[i];
        }
        else
        {
            if(tmp.size()>0)
            {
                dict[tmp]++;
            }
            tmp="";
        }
    }
    if(tmp.size()>0)//注意最后一次要判断一下,不然最后的单词加不进去了。
        dict[tmp]++;
    int maxn=-1;
    string res;
    for (auto & d:dict)
    {
        if(d.second>maxn)
        {

            res=d.first;
            maxn=d.second;
        }
    }
    cout<<res<<" "<<dict[res];
    return 0;
}

1072[多重Dijkstra]

Gas Station

思路:把所有居民楼和加油站都作为结点,其中加油站编号N+1开始。然后对每个加油站,运用Dijkstra求其到所有居民楼的距离,然后找到一个离所有居民楼最短距离中最远的那一个即可。顺便计算平均距离。

//
// @author prime on 2017/7/1.
//

#include <iostream>
#include <algorithm>

using namespace std;

const int inf=99999999;

int G[1020][1020];
bool visited[1020];
int dis[1020];

int main()
{
    int N,M,K,Ds;
    scanf("%d%d%d%d",&N,&M,&K,&Ds);
    fill(G[0],G[0]+1020*1020,inf);
    for (int i=0;i<K;++i)
    {//加油站编号为[N+1,
        int u,v,d;
        string tmp_u,tmp_v;
        cin>>tmp_u>>tmp_v>>d;
        if(tmp_u[0]=='G')
        {
            u=stoi(tmp_u.substr(1))+N;
        } else
            u=stoi(tmp_u);
        if(tmp_v[0]=='G')
            v=stoi(tmp_v.substr(1))+N;
        else
            v=stoi(tmp_v);
        G[u][v]=d;
        G[v][u]=d;
    }
    int res_id=-1;
    double res_dis=inf,min_dis=-1;//平均距离,离居民的最近距离
    for (int index=N+1;index<=N+M;++index)
    {//对每个加油站求其到任意居民楼的最短距离
        fill(visited,visited+1020, false);
        fill(dis,dis+1020,inf);
        dis[index]=0;
        for (int i=1;i<=N+M;++i)
        {//松弛N+M轮
            int u=-1,min_d=inf;
            for (int j=1;j<=N+M;j++)
            {
                if(dis[j]<min_d&&!visited[j])
                {
                    u=j;
                    min_d=dis[j];
                }
            }
            if(u==-1)
                break;
            visited[u]=true;
            for (int v=1;v<=N+M;v++)
            {
                if(!visited[v]&&G[u][v]!=inf)
                {
                    if(G[u][v]+dis[u]<dis[v])
                        dis[v]=G[u][v]+dis[u];
                }
            }
        }
        double tmp_dis=0,tmp_min=inf;//到所有居民的平均距离,最近距离
        bool valid=true;
        for (int i=1;i<=N;++i)
        {
            tmp_dis+=dis[i];
            if(dis[i]>Ds)
            {
                valid=false;
                break;
            }
            if(dis[i]<tmp_min)
            {
                tmp_min=dis[i];
            }
        }
        if(valid)
        {//这个加油站位置距离可以服务全部居民
            tmp_dis/=N;
            if(tmp_min>min_dis)//优先找离居民的最短距离最大的
            {
                res_dis=tmp_dis;
                res_id=index-N;
                min_dis=tmp_min;
            }
            else if(tmp_min==min_dis&&tmp_dis<res_dis)//次之找平均距离最短的
            {
                res_id=index-N;
                res_dis=tmp_dis;
            }
        }
    }
    if(res_id==-1)
    {
        printf("No Solution");
        return 0;
    }
    printf("G%d\n",res_id);
    printf("%.1lf %.1lf",min_dis,res_dis);
    return 0;
}

1073[科学计数法]

Scientific Notation

思路:和以前的科学计数法思路相近,先求指数,然后看情况补0,最后插入小数点。

//
// @author prime on 2017/7/2.
//

#include <iostream>

using namespace std;

int main()
{
    bool sign;
    string in,res;
    cin>>in;
    sign= (in[0]=='+');
    int exponent=0;//题目说了指数不超过9999
    for (int i=1;i<in.size();++i)
    {
        if(in[i]=='E')
        {
            exponent=stoi(in.substr(i+1));
            break;
        }
        if(in[i]!='.')
            res+=in[i];
    }//res保存系数部分,不保存小数点。
    if(exponent>0)
    {
        if(exponent>res.size()-1)
        {
            res.insert(res.size(),exponent-(res.size()-1),'0');
        } else if(exponent<res.size()-1)
        {
            res.insert(1+exponent,1,'.');
        }
    } else if(exponent<0)
    {
        exponent=-exponent;
        res.insert(0,exponent,'0');
        res.insert(1,1,'.');
    }
    else
    {
        res.insert(1,1,'.');
    }
    if(!sign)
        res='-'+res;
    cout<<res;
    return 0;
}

1074[翻转链表/reverse函数的使用]

Reversing Linked List

思路:目前遇到的所有链表题都一个共性,每个结点地址和值是一一对应的,其它的可变,所以,完全可以用数组模拟,标准库reverse函数一上,秒杀。

//
// @author prime on 2017/7/2.
//

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct Node
{
    int address;//5位
    int val;
    int next;
};


int main()
{
    int start,N,K;
    scanf("%d%d%d",&start,&N,&K);
    vector<Node> in(100000),res;
    for (int i=0,addr;i<N;++i)
    {
        scanf("%d",&addr);
        scanf("%d%d",&in[addr].val,&in[addr].next);
        in[addr].address=addr;
    }
    for (int begin=start;begin!=-1;begin=in[begin].next)
        res.push_back(in[begin]);
    for (auto it=res.begin();it<res.end();it+=K)
        if(it+K<=res.end())
            reverse(it,it+K);
    for (int i=0;i<res.size();++i)
    {
        if(i==res.size()-1)
        {
            printf("%05d %d -1",res[i].address,res[i].val);
            break;
        }
        printf("%05d %d %05d\n",res[i].address,res[i].val,res[i+1].address);
    }
    return 0;
}

1075[多阶段排序]

思路:还是老生常谈的排序,注意这个题几个点:未提交任何题目,或者提交的都没通过编译的不输出!否则就算0分也要输出。我这里用了个标志位valid,所以排序时要先按valid排序再根据id排,不然可能提前遇到了valid为false的,但是后面还有valid为true的呢!另外,第一个元素不用,排序的时候不要再排它了!!!

//
// @author prime on 2017/7/2.
//


#include <iostream>
#include <algorithm>

using namespace std;

struct People
{
    int id;
    int score[6];//5道题得分情况
    int total_score;
    int perfect_num;//完美通过的题目数量;
    int rank;//最后的排名
    bool valid;
};

bool cmp(const People&o1,const People&o2)
{
    if(o1.total_score!=o2.total_score)
        return o1.total_score>o2.total_score;
    else if(o1.perfect_num!=o2.perfect_num)
        return o1.perfect_num>o2.perfect_num;
    else if(o1.valid!=o2.valid)//必须加上这个,不然最后一个过不去
        return o1.valid>o2.valid;
    else
        return o1.id<o2.id;
}

int main()
{
    int N,K,M;
    scanf("%d%d%d",&N,&K,&M);
    int p[10];//五道题的分值
    for (int i=1;i<=K;++i)
        scanf("%d",&p[i]);
    vector<People> in(N+1);
    for (int i=1;i<=N;++i)
    {
        fill(in[i].score,in[i].score+6,-2);//一开始得分全部是-2
        /*in[i].total_score=0;
        in[i].valid=false;
        in[i].perfect_num=0;*/
    }
    for (int i=0;i<M;++i)
    {
        int id,problem_id,score;
        scanf("%d%d%d",&id,&problem_id,&score);
        if(in[id].score[problem_id]>=score)
            continue;
        else
        {
            in[id].id=id;
            if(score>=0)
            {//这次成绩有效
                in[id].valid=true;//有一个得分为正表示有效
                if(in[id].score[problem_id]>0)
                    in[id].total_score+=score-in[id].score[problem_id];
                else
                    in[id].total_score+=score;
            }
            in[id].score[problem_id]=score;
            if(score==p[problem_id])
            {
                in[id].perfect_num++;
            }
        }
    }
    sort(in.begin()+1,in.end(),cmp);
    in[1].rank=1;
    for (int i=2;i<in.size();++i)
    {
        if(!in[i].valid)
            break;
        if(in[i].total_score==in[i-1].total_score)
            in[i].rank=in[i-1].rank;
        else
            in[i].rank=i;
    }
    for (int k=1;k<in.size();++k)
    {
        if(!in[k].valid)
            break;
        printf("%d %05d %d ",in[k].rank,in[k].id,in[k].total_score);
        for (int i=1;i<=K;++i)
        {
            if(in[k].score[i]>=0)
                printf("%d",in[k].score[i]);
            else if(in[k].score[i]==-1)//-1表示没有通过编译
                printf("0");
            else//等于-2表示从来没提交过
                printf("-");
            if(i!=K)
                printf(" ");
        }
        printf("\n");
    }
    return 0;
}

1076[限制最大深度的BFS]

Forwards on Weibo

和1004的背景相似。

思路:一开始输入只给出了每个人关注的用户,只需要转换一下思路就可以变成每个人的follower。运用BFS对有向图进行广度优先遍历即可,注意需要判断深度。另外,一开始的起点深度为0,且起点发的文章不计入统计。

//
// @author prime on 2017/7/3.
//

#include <iostream>
#include <vector>
#include <deque>
using namespace std;

int N,L;
vector <vector<int>> G;
bool visited[1005];

struct Node
{
    int id;
    int layer;//第几层
};

int BFS(int u)
{//返回总共转发的次数
    fill(visited,visited+1005, false);
    deque<Node> queue;
    //头结点入队列
    Node top;
    top.id=u;
    top.layer=0;
    queue.push_back(top);
    visited[u]=true;//visited保证每个元素只进一次队列
    int res=0;
    while(!queue.empty())
    {
        top=queue[0];
        queue.pop_front();

        for (int i=0;i<G[top.id].size();i++)
        {
            Node next;
            if(!visited[G[top.id][i]]&&top.layer<L)
            {
                next.id=G[top.id][i];
                next.layer=top.layer+1;
                queue.push_back(next);
                visited[G[top.id][i]]=true;
                res++;//不能再pop的时候统计,因为这样起点也算进来了,起点不算的。
            }
        }
    }
    return res;
}

int main()
{
    scanf("%d%d",&N,&L);
    G.resize(N+1);
    for (int i=1;i<=N;++i)
    {
        int k;
        scanf("%d",&k);
        for (int j=0;j<k;++j)
        {
            int id;
            scanf("%d",&id);
            G[id].push_back(i);
            /*注意不是G[i].push_back(id),只有这样得到的G[id]才是每个id的follower*/
        }
    }
    int K;
    scanf("%d",&K);
    for (int i=0;i<K;++i)
    {
        int query;
        scanf("%d",&query);
        printf("%d\n",BFS(query));
    }
    return 0;
}

1077[最长字符串后缀]

Kuchiguse

思路:后缀比对起来比较麻烦,在输入一个字符串后顺便反转它就好了。然后比对前缀,一开始res等于s[0],然后比对s[1]到s[N],不相等就截取一段。最后看res是否是空串,不是就倒序输出。

一开始直接用后缀比较了,结果最后一个用例过不去,,不知道为什么。。

//
// @author prime on 2017/7/3.
//

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

int main()
{
    int N;
    cin>>N;
    getchar();//吃掉换行符
    string s[N];
    for (int i=0;i<N;++i)
    {
        getline(cin,s[i]);
        reverse(s[i].begin(),s[i].end());
    }
    string res=s[0];
    for (int i=1;i<N;++i)
    {
        int end=min((int)res.size(),(int)s[i].size());
        for (int k=0;k<end;k++)
        {
            if(res[k]!=s[i][k])
            {
                res=res.substr(0,k);
                break;
            }
        }
    }
    if(res.size()==0)
        cout<<"nai";
    else
    {
        for (auto it=res.rbegin();it!=res.rend();it++)
            cout<<*it;
    }
    return 0;
}

1078[散列表二次探测]

Hashing

思路:如果知道Quadratic probing是二次探测就没问题了,此处只要求递增的二次探测。

记住,这种题没必要真的插入数字,只有记录有没有即可,所以果断用bool

//
// @author prime on 2017/7/3.
//

#include <iostream>
#include <cmath>
#include <vector>
using namespace std;

bool isprime(int M)
{
    if(M<=1)
        return false;
    for(int i=2;i<=sqrt(M);i++)
    {
        if(M%i==0)
            return false;
    }
    return true;
}

int main()
{
    int M,N;
    scanf("%d%d",&M,&N);
    while(!isprime(M))
    {
        M++;
    }
    vector<bool > a(M, false);
    for (int i=0;i<N;++i)
    {
        int num,pos;
        scanf("%d",&num);
        pos=num%M;
        if(!a[pos])
        {
            printf("%d",pos);
            a[pos]=true;
        }
        else
        {
            bool flag=false;
            for (int step=1;step<M;step++)
            {
                pos=(num+step*step)%M;
                if(!a[pos])
                {
                    flag=true;
                    printf("%d",pos);
                    a[pos]=true;
                    break;
                }
            }
            if(!flag)
                printf("-");
        }
        if(i!=N-1)
            printf(" ");
    }
    return 0;
}

1079[树的DFS]

Total Sales of Supply Chain

思路:经典题目,树的DFS遍历。用product数组保存零售商的货品数量。

//
// @author prime on 2017/7/4.
//
#include <iostream>
#include <vector>


using namespace std;

double total_sale=0;

double R;

vector<int> tree[100000];
int product[100000];//记录零售商i的商品数量

void DFS(int u, double price)
{
    if(tree[u].size()==0)
    {
        total_sale+=product[u]*price;
    }
    else
    {
        for (int i=0;i<tree[u].size();++i)
            DFS(tree[u][i],(1+R)*price);
    }
}


int main()
{
    int N;
    double P;
    scanf("%d %lf %lf",&N,&P,&R);
    R/=100;
    for (int i=0;i<N;++i)
    {
        int num;
        scanf("%d",&num);
        if(num==0)
        {
            scanf("%d",&product[i]);
            continue;
        }
        for (int j=0;j<num;++j)
        {
            int id;
            scanf("%d",&id);
            tree[i].push_back(id);
        }
    }
    DFS(0,P);
    printf("%.1lf",total_sale);
    return 0;
}

1080[复杂排序]

Graduate Admission

思路:还是经典的排序,我一开始的思路是用rank和target记录上一个人的排名和选的学校,然后看下一个人是不是一样,一样就录取(用于学校名额满的情况),但是这种有问题,虽然ac了,但是确实不符合题意,比如如下用例

3 2 1
1 1
100 100 0
100 100 1
100 100 0

按理说,0号和2号都应该进入学校0才对,但是如果用这样2号就会进不去!

所以,更健全的思路是用一个结构体保存一个一个学校的最后一名,这样就没问题了。所以,这种可能会”交叉”的情况,还是应该仔细考虑是用一个变量保存还是用一组变量保存。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct Student
{
    int id;
    int Ge,Gi;
    int choice[5];
    int rank;
    int total;
};

struct School
{
    int last_rank;//招收的最后一个的学生的排名
    int num;//收多少人
    vector<int> receive;
};

bool cmp(const Student& o1,const Student&o2)
{
    if(o1.total!=o2.total)
        return o1.total>o2.total;
    else if(o1.Ge!=o2.Ge)
        return o1.Ge>o2.Ge;
    else return o1.id<o2.id;
}

int main()
{
    int N,M,K;
    scanf("%d%d%d",&N,&M,&K);
    vector<School> sch(M);
    vector<Student> stu(N);
    for (int i=0;i<M;++i)
    {
        scanf("%d",&sch[i].num);
    }
    for (int i=0;i<N;++i)
    {
        scanf("%d%d",&stu[i].Ge,&stu[i].Gi);
        for (int j=0;j<K;j++)
            scanf("%d",&stu[i].choice[j]);
        stu[i].total=(stu[i].Ge+stu[i].Gi)/2;
        stu[i].id=i;
    }
    sort(stu.begin(),stu.end(),cmp);
    stu[0].rank=1;
    for (int i=1;i<N;i++)
    {
        if(stu[i].total==stu[i-1].total&&stu[i].Ge==stu[i-1].Ge)
        {
            stu[i].rank=stu[i-1].rank;
        }
        else
        {
            stu[i].rank=i+1;
        }
    }
    for (int i=0;i<N;++i)
    {
        int prefer;
        for (int j=0;j<K;++j)
        {
            prefer=stu[i].choice[j];
            if(sch[prefer].num>0)
            {
                sch[prefer].num--;
                sch[prefer].receive.push_back(stu[i].id);
                sch[prefer].last_rank=stu[i].rank;
                break;
            }
            else if(sch[prefer].last_rank==stu[i].rank)
            {
                sch[prefer].receive.push_back(stu[i].id);
                break;
            }
        }
    }
    for (int i=0;i<M;i++)
    {
        if(sch[i].receive.size()==0)
            printf("\n");
        else
        {
            sort(sch[i].receive.begin(),sch[i].receive.end());
            for (int j=0;j<sch[i].receive.size();++j)
            {
                printf("%d",sch[i].receive[j]);
                if(j!=sch[i].receive.size()-1)
                    printf(" ");
            }
            printf("\n");
        }
    }
    return 0;
}

最后把虽然ac但是不对的代码也附上吧

//
// @author prime on 2017/7/4.
//

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct Student
{
    int id;
    int Ge,Gi;
    int choice[5];
    int rank;
    int total;
};

bool cmp(const Student& o1,const Student&o2)
{
    if(o1.total!=o2.total)
        return o1.total>o2.total;
    else
        return o1.Ge>o2.Ge;//把这个换成下面注释掉的也一样!!!
    /*else if(o1.Ge!=o2.Ge)
        return o1.Ge>o2.Ge;
    else return o1.id<o2.id;*/
} /*如果一个元素既不大于又不小于另一个元素,它们就相等*/

int main()
{
    int N,M,K;
    scanf("%d%d%d",&N,&M,&K);
    vector<int> quota(M);//各个学校名额
    vector<int> res[M];
    vector<Student> stu(N);
    for (int i=0;i<M;++i)
        scanf("%d",&quota[i]);
    for (int i=0;i<N;++i)
    {
        scanf("%d%d",&stu[i].Ge,&stu[i].Gi);
        for (int j=0;j<K;j++)
            scanf("%d",&stu[i].choice[j]);
        stu[i].total=(stu[i].Ge+stu[i].Gi)/2;
        stu[i].id=i;
    }
    sort(stu.begin(),stu.end(),cmp);
    stu[0].rank=1;
    for (int i=1;i<N;i++)
    {
        if(stu[i].total==stu[i-1].total&&stu[i].Ge==stu[i-1].Ge)
        {
            stu[i].rank=stu[i-1].rank;
        }
        else
        {
            stu[i].rank=i+1;
        }
    }
    int rank=-1,target=-1;//记录上一个人的排名和他选的学校
    for (int i=0;i<N;++i)
    {
        for (int j=0;j<K;j++)
        {
            int prefer=stu[i].choice[j];
            if(quota[prefer]>0)
            {
                rank=stu[i].rank;
                target=prefer;
                quota[prefer]--;
                res[prefer].push_back(stu[i].id);
                break;
            }
            else if(stu[i].rank==rank&&prefer==target)
            {
                res[prefer].push_back(stu[i].id);
                break;
            }
        }
    }
    for (int i=0;i<M;i++)
    {
        if(res[i].size()==0)
            printf("\n");
        else
        {
            sort(res[i].begin(),res[i].end());
            for (int j=0;j<res[i].size();++j)
            {
                printf("%d",res[i][j]);
                if(j!=res[i].size()-1)
                    printf(" ");
            }
            printf("\n");
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值