• 2018-2019 ICPC Northwestern European Regional Programming Contest (NWERC 2018)训练记录


    B    Brexit Negotiations

    题意:有n个会议,对于会议i,它将花费时间ci,并需要在进行前先完成指定的di个会议。在每个会议中,将为在它之前进行的每个会议各花费1个单位的时间。现在要为这n个会议进行排序,使得其中进行时间最长的会议时间最短。

    思路:从每个会议进行前需要完成若干个指定会议这一点可以看出,

    可以在(会议i)<--(会议i进行前需要进行的会议)之间连有向边,使用拓扑排序就可求出会议进行顺序。

    对于第i个进行的会议,它的时长为c+i。

    粗略地想,我们应当选择当前能够进行并且时间最长的会议,

    于是想到使用优先队列,在拓扑排序过程中,将ci值大的先取出进行删边。

    但是仔细一想,这种贪心没有考虑到当前不满足进行条件但时间很长的会议。

    于是先使用dfs,求出所有需要先进行会议i的(cj+(会议i与会议j的距离))的最大值dis[i],将dis值大的先取出进行删边。

    (具体看代码)

    。。看了一圈题解,发现只要反向建边就可以直接拓扑了。啊这。。

    #include<cstdio>
    #include<queue>
    #include<algorithm>
    using namespace std;
    const int maxn=400005;
    struct node
    {
        int id,dis,t;
        node() {}
        node(int a,int b,int c) 
        {
            id=a;
            dis=b;
            t=c;
        }
        bool operator < (const node &b) const
        {
            return dis<b.dis;
        }
    };
    priority_queue<node>q;
    int n,a[maxn],in[maxn],last[maxn],num;
    int dis[maxn],vis[maxn],ans;
    struct edge
    {
        int to,nxt;
    }e[maxn];
    void add(int x,int y)
    {
        e[++num].to=y;
        e[num].nxt=last[x];
        last[x]=num;
    }
    int topo()
    {
        for (int i=1;i<=n;i++) 
            if (!in[i]) q.push(node(i,dis[i],a[i]));
        int now=0,ans=0;
        node x;
        while (!q.empty())
        {
            x=q.top();
            q.pop();
            ans=max(ans,now+x.t);
            now++;
            for (int i=last[x.id];i;i=e[i].nxt)
            {
                in[e[i].to]--;
                if (in[e[i].to]==0) q.push(node(e[i].to,dis[e[i].to],a[e[i].to]));
            }
        } 
        return ans;
    }
    void dfs(int x)
    {
        vis[x]=1;
        dis[x]=a[x];
        for (int i=last[x];i;i=e[i].nxt)
        {
            if (!vis[e[i].to]) dfs(e[i].to);
            dis[x]=max(dis[x],dis[e[i].to]+1);
        }
    } 
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i],&in[i]);
            for (int j=1,u;j<=in[i];j++)
            {
                scanf("%d",&u);
                add(u,i);
            }
        }
        for (int i=1;i<=n;i++)
            if (!in[i]) dfs(i);
        printf("%d
    ",topo());
        return 0;
    }
    View Code

    G

    题意:有一个n*n的迷宫,迷宫中有若干个方块。球从某个起点开始,要最终走到终点(0,0)。每次操作可以走上下左右四个方向,直至碰到方块或者边界球才停止。现在给出一串操作,要求设计球的起点和迷宫中方块的分布,使得球能够根据这串操作走至终点。

    思路:一开始想着从终点开始倒着做,发现很难想。看了别人的代码,发现直接正着做会好做一点。

    ()

    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    using namespace std;
    vector<pair<int,int> >a;
    int dir[100];
    char s[25];
    int main()
    {
        int i,x=0,y=0,len,r=1;//先假装起点为0,0 
        scanf("%s",s);
        dir['R']=dir['L']=1;
        dir['U']=dir['D']=2;
        len=strlen(s); 
        if (len>=3 && s[len-1]==s[len-3] && dir[s[len-1]]==dir[s[len-2]])
        {
            printf("impossible
    ");
            return 0;
        }
        for (i=0;i<len;i++)
        {
            if (i<len-1 && dir[s[i]]!=dir[s[i-1]]) r++;
            if (s[i]=='R') 
            { 
                x=r;
                a.push_back({x+1,y}); 
            }
            else if (s[i]=='L') 
            {
                x=-r; 
                a.push_back({x-1,y}); 
            }
            else if (s[i]=='U') 
            {
                y=r; 
                a.push_back({x,y+1});
            }
            else if (s[i]=='D') 
            {
                y=-r; 
                a.push_back({x,y-1}); 
            }
        }
        for (i=0;i<a.size();i++)
        {
            a[i].first-=x;
            a[i].second-=y;
        }
        sort(a.begin(),a.end());
        a.erase(unique(a.begin(),a.end()),a.end());//去重 
        printf("%d %d
    ",-x,-y);//根据终点为0,0,修改起点坐标为0-x,0-y 
        printf("%d
    ",a.size());
        for (i=0;i<a.size();i++) printf("%d %d
    ",a[i].first,a[i].second);
        return 0;
    }
    View Code

    H    Hard Drive

    I    Inflation

    题意:有n个气球,容量从1到n,同时有n个气瓶,有a[i]容量的气。当给气球充气的气瓶的容量大于气球的,那么气球就会爆炸,

    找出一种气球与气瓶的配对,使得没有气球爆炸并且所有配对中a[i]/i的最小值最大,输出这个最小值。

    思路:直接将a排序,然后两两配对就行了。

    注意答案直接输出就行了,special judge

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=200005;
    int a[maxn];
    int main()
    {
        int i,n,flag;
        double ans,tmp;
        scanf("%d",&n);
        for (i=1;i<=n;i++) scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        ans=1.0;
        flag=0;
        for (i=1;i<=n;i++)
        {
            if (a[i]>i) 
            {
                flag=1;
                break;
            }
            else 
            {
                tmp=(double)a[i]/i;
                ans=min(ans,tmp);
            }
        }
        if (!flag) printf("%lf
    ",ans);
        else printf("-1
    ");
        return 0;
    } 
    View Code

    K    Kleptography

  • 相关阅读:
    PHP单引号和双引号的区别
    thinkphp实现导航高亮的简单方法
    js选中当前菜单后高亮显示的导航条
    Dubbo新版管控台
    把本人基于Dubbo的毕业设计分享粗来~
    Windows 查看端口占用情况
    GitLab 环境搭建【CentOS7】
    【非专业前端】vue+element+webpack
    【非专业前端】使用vue2.5.17+element2.4.5
    ElasticSearch6.3.2------入门
  • 原文地址:https://www.cnblogs.com/lsykk/p/13768723.html
Copyright © 2020-2023  润新知