zoukankan      html  css  js  c++  java
  • BUCT2020春季学期ACM周赛-11

    BUCT2020春季学期ACM周赛-11

    A-冲浪游戏(cf 900)

    思路

    贪心,本题考虑求解最小的扣款钱数,所以容易想到本体题按扣款的钱数从大到小排序(尽可能把扣款最多的游戏放到执行队列中,以减少扣款钱数),那么在按顺序遍历每个游戏,考虑游戏的执行时间,将当前游戏放到截止时间之前的时间段的最后一个未占用时间段内,如果无法找到一个时间段,那么将此游戏放到全时间段的最后一个未占用时间段(因为放在哪都是要扣款的,所以尽可能往后放,为其他游戏腾出时间)。

    Code
    /****************************************************
    /@Author: Kirito
    /@TIME:   2020-04-30
    /@FILENAME: chonglang.cpp
    /@REMARK:    
    /****************************************************/
    #include <bits/stdc++.h>
    #define lowbit(x) (x&(-x))
    #define CSE(x,y) memset(x,y,sizeof(x))
    #define INF 0x3f3f3f3f
    #define Abs(x) (x>=0?x:(-x))
    #define FAST ios::sync_with_stdio(false);cin.tie(0);
    using namespace std;
     
    typedef long long ll;
    typedef pair<int,int> pii;
    typedef pair<ll , ll> pll;
     
    const int maxn=1000;
    int n,m,book[maxn];
    struct game{
        int t,w;
        bool operator < (const game &x)const{
            return this->w>x.w;
        }
    }arr[maxn];
     
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("in.in","r",stdin);
    #endif
        FAST;
        cin>>m>>n;
        for(int i=1;i<=n;i++){
            cin>>arr[i].t;
        }
        for(int i=1;i<=n;i++){
            cin>>arr[i].w;
        }
        sort(arr+1,arr+n+1);
        for(int i=1;i<=n;i++){
            bool fl=true;
            for(int j=arr[i].t;j>=1;j--){
                if(book[j]==0){
                    book[j]=1;fl=false;break;
                }
            }
            if(fl){
                m-=arr[i].w;
                for(int j=n;j>=1;j--)
                    if(book[j]==0){
                        book[j]=1;break;
                    }
            }
        }
        cout<<m<<endl;
        return 0;
    }
    

    B-最短Hamiton路径(cf 1400)

    思路

    用二进制上的数代表一个点的状态,取(1)或不取(0)。题目让求从点1到n的最短汉密顿路径,即经过每个点一次,这时的状态用二进制表示就是 ((1<<n)-1 (n个1))。用(dp[i][j])表示在状态 (i) 下,从(1)(j) 的最短汉密顿路径。

    (dp[i][j])可由上一个状态(上一状态就是把 j从当前状态中去掉)(dp[i^(1<<(j-1))][k])得到,其中保证(k)是中存在的点,即 $ (i>>k) & 1 $。

    表示$ i$ 的第 (k) 位是(1),即经过点 (k)。 注意是$ i>>k$ 不是 (i<<k)

    则状态转移方程为:(dp[i][j]=min{dp[i^(1<<j)][k]+Map[k][j]}(k=1~n)); 其含义就是枚举到达点(j)之前的前一个点(k),取其最短。

    Code
    #include <cstdio>
    #include <iostream>
    #include <queue>
    #include <cstring>
    #define Inf 0x3f3f3f
    #define ll long long
    using namespace std;
    int dp[(1<<20)+5][25];
    int maze[25][25];
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                scanf("%d",&maze[i][j]);
        memset(dp,Inf,sizeof(dp));
        dp[1][0]=0;
        for(int i=1;i<=(1<<n)-1;i++)
        {
            for(int j=0;j<n;j++)
            {
                if((i>>j)&1)//如果i的第j位是1,也就是如果经过点j
                {
                    for(int k=0;k<n;k++)
                    {
                        if((i>>k)&1)//如果i的第k位是1,也就是如果经过点k
                        {
                            dp[i][j]=min(dp[i][j],dp[i^(1<<j)][k]+maze[k][j]);
                        }
                    }
                }
            }
        }
        printf("%d
    ",dp[(1<<n)-1][n-1]);
     
        return 0;
    }
    

    C-假设电话线(cf 1600)

    思路

    二分加最短路,对于本题的结果,可以发现具有但单调性,所以我们可用二分来枚举结果,然后对原图进行加工,对于大于二分值的权边,置为1,否则置为0,然后用Dijkstra计算最短路判断最后到n的值是否大于k。

    Code
    /****************************************************
    /@Author: Kirito
    /@TIME:   2020-05-03
    /@FILENAME: telephonlines.cpp
    /@REMARK:    
    /****************************************************/
    #include <bits/stdc++.h>
    #define lowbit(x) (x&(-x))
    #define CSE(x,y) memset(x,y,sizeof(x))
    #define INF 0x3f3f3f3f
    #define Abs(x) (x>=0?x:(-x))
    #define FAST ios::sync_with_stdio(false);cin.tie(0);
    using namespace std;
    
    typedef long long ll;
    typedef pair<int,int> pii;
    typedef pair<ll , ll> pll;
    
    const int maxn=5000;
    //information
    int n,m,k;
    //graph1
    int head1[maxn],next1[maxn],v[maxn],w[maxn],cnt;
    //dijk
    int dist[maxn],book[maxn];
    
    void add(int x,int y,int z){
        v[++cnt]=y;w[cnt]=z;
        next1[cnt]=head1[x];head1[x]=cnt;
        return;
    }
    
    bool Dijkstra(int bl){
        CSE(dist,INF);CSE(book,0);
        priority_queue<pii,vector<pii>,greater<pii>> box;
        dist[1]=0;box.push(make_pair(dist[1],1));
        while(!box.empty()){
            int x=box.top().second;int d=box.top().first;box.pop();
            if(book[x]) continue;
            book[x]=1;
            for(int i=head1[x];i!=-1;i=next1[i]){
                int y=v[i];int kk=(w[i]>=bl?1:0);
                if(dist[y]>kk+d){
                    dist[y]=kk+d;
                    box.push(make_pair(dist[y],y));
                }
            }
        }
        return dist[n]>k;
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("in.in","r",stdin);
    #endif
        FAST;
        CSE(head1,-1);CSE(next1,-1);
        cin>>n>>m>>k;
        for(int i=0;i<m;i++){
            int x,y,z;
            cin>>x>>y>>z;
            add(x,y,z);add(y,x,z);
        }
        int l=0,r=1000001,ans=-1;
        while(l<=r){
            int mid=(l+r)/2;
            if(Dijkstra(mid)) l=mid+1,ans=mid;
            else r=mid-1;
        }
        if(ans>1000000) ans=-1;
        if(r<0) ans=0;
        cout<<ans<<endl;
        return 0;
    }
    

    D-农场派对(cf 1500)

    思路

    对于去时的最短路径直接用Dijkstra算法求解即可,对于回来时的最短路径,将所有的有向边方向反转,权值不改变,之后按去时的路径求解最短路径,将两个最短路径的值加和就是最短的来回路径,遍历所有顶点求取最短路径最大值即可。

    Code
    /****************************************************
    /@Author: Kirito
    /@TIME:   2020-04-30
    /@FILENAME: fanxiangbian.cpp
    /@REMARK:    
    /****************************************************/
    #include <bits/stdc++.h>
    #define lowbit(x) (x&(-x))
    #define CSE(x,y) memset(x,y,sizeof(x))
    #define INF 0x3f3f3f3f
    #define Abs(x) (x>=0?x:(-x))
    #define FAST ios::sync_with_stdio(false);cin.tie(0);
    using namespace std;
     
    typedef long long ll;
    typedef pair<int,int> pii;
    typedef pair<ll , ll> pll;
     
    const int maxn=111111;
    //graph1
    int first[maxn],nxt1[maxn],u1[maxn],v1[maxn],w[maxn];
    int cnt,n,m,s;
    //graph2
    int head[maxn],nxt2[maxn],u2[maxn],v2[maxn];
    //dij
    int dist1[maxn],dist2[maxn];
    //邻接表
    void add(int x,int y,int d){
        u1[++cnt]=x;v1[cnt]=y;
        u2[cnt]=y;v2[cnt]=x;
        w[cnt]=d;
        nxt1[cnt]=first[u1[cnt]];first[u1[cnt]]=cnt;
        nxt2[cnt]=head[u2[cnt]];head[u2[cnt]]=cnt;
        return;
    }
     
    void Dijkstra1(int s){
        CSE(dist1,INF);
        priority_queue<pii,vector<pii>,greater<pii>> box;
        dist1[s]=0;box.push(make_pair(0,s));
        while(!box.empty()){
            int x=box.top().second;
            int d=box.top().first;
            box.pop();
            for(int i=first[x];i!=-1;i=nxt1[i]){
                int y=v1[i];
                if(dist1[y]>d+w[i]){
                    dist1[y]=d+w[i];
                    box.push(make_pair(dist1[y],y));
                }
            }
        }
        return;
    }
     
    void Dijkstra2(int s){
        CSE(dist2,INF);
        priority_queue<pii,vector<pii>,greater<pii>> box;
        dist2[s]=0;box.push(make_pair(0,s));
        while(!box.empty()){
            int x=box.top().second;
            int d=box.top().first;
            box.pop();
            for(int i=head[x];i!=-1;i=nxt2[i]){
                int y=v2[i];
                if(dist2[y]>d+w[i]){
                    dist2[y]=d+w[i];
                    box.push(make_pair(dist2[y],y));
                }
            }
        }
        return;
    }
     
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("in.in","r",stdin);
    #endif
        FAST;
        CSE(first,-1);CSE(nxt1,-1);CSE(head,-1);CSE(nxt2,-1);
        cin>>n>>m>>s;
        for(int i=0;i<m;i++){
            int x,y,d;
            cin>>x>>y>>d;
            add(x,y,d);
        }
        Dijkstra1(s);
        Dijkstra2(s);
        int ans=0;
        for(int i=1;i<=n;i++){
            ans=max(ans,dist1[i]+dist2[i]);
        }
        cout<<ans<<endl;
        return 0;
    }
    

    E-Roadblocks(cf 1400)

    思路

    Dijkstra次短路径板题,用一个数组(dist1[])记录最短路径,另一个数组(dist2[])记录次短路径,执行Dijkstra算法。

    当要更新最短路时执行

    1. 更新次短路径为当前最短路径的值
    2. 更新最短路径为新的最短路径的值

    当不需要更新最短路但是新的路径长度大于最短路径,但是小于次短路径时执行

    1. 更新次短路径为新的路径值
    Code
    /****************************************************
    /@Author: Kirito
    /@TIME:   2020-04-30
    /@FILENAME: cidunalu.cpp
    /@REMARK:    
    /****************************************************/
    #include <bits/stdc++.h>
    #define lowbit(x) (x&(-x))
    #define CSE(x,y) memset(x,y,sizeof(x))
    #define INF 0x3f3f3f3f
    #define Abs(x) (x>=0?x:(-x))
    #define FAST ios::sync_with_stdio(false);cin.tie(0);
    using namespace std;
     
    typedef long long ll;
    typedef pair<int,int> pii;
    typedef pair<ll , ll> pll;
     
    const int maxn=211111;
    //graph
    int first[maxn],nxt[maxn],w[maxn],u[maxn],v[maxn];
    int n,m,cnt;
    //dijkstra
    int dis[maxn],ans[maxn];
    //邻接表
    void add(int x,int y,int d){
        u[++cnt]=x;v[cnt]=y;w[cnt]=d;
        nxt[cnt]=first[u[cnt]];first[u[cnt]]=cnt;
        return;
    }
     
    void Dijkstra(int s){
        CSE(dis,INF);CSE(ans,INF);
        priority_queue<pii,vector<pii>,greater<pii>> box;
        dis[s]=0;box.push(make_pair(0,s));
        while(!box.empty()){
            int x=box.top().second;
            int d=box.top().first;
            box.pop();
            for(int i=first[x];i!=-1;i=nxt[i]){
                int y=v[i];
                if(dis[y]>d+w[i]){
                    ans[y]=dis[y];
                    dis[y]=d+w[i];
                    box.push(make_pair(dis[y],y));
                }
                else if(dis[y]==d+w[i]) continue;
                else if(ans[y]>d+w[i]&&dis[y]<d+w[i]){
                    ans[y]=d+w[i];
                    box.push(make_pair(ans[y],y));
                }
            }
        }
        return;
    }
     
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("in.in","r",stdin);
    #endif
        FAST;
        CSE(first,-1);CSE(nxt,-1);
        cin>>n>>m;
        for(int i=0;i<m;i++){
            int x,y,d;
            cin>>x>>y>>d;
            add(x,y,d);add(y,x,d);
        }
        Dijkstra(1);
        cout<<ans[n]<<endl;
        return 0;
    }
    

    F-最短路计数(cf 1400)

    思路

    Dijkstra简单变体,在计算最短路时,考虑两种情况,当需要更新最短路时,将当前节点的最短路径个数等于出发节点的最短路径个数,当不需要更新最短路径,但是当前路径和最短路径的值相等时,将当前最短节点的最短路径的个数加上出发节点的最短路径的个数。

    Code
    /****************************************************
    /@Author: Kirito
    /@TIME:   2020-04-30
    /@FILENAME: counzuiduanlu.cpp
    /@REMARK:    
    /****************************************************/
    #include <bits/stdc++.h>
    #define lowbit(x) (x&(-x))
    #define CSE(x,y) memset(x,y,sizeof(x))
    #define INF 0x3f3f3f3f
    #define Abs(x) (x>=0?x:(-x))
    #define FAST ios::sync_with_stdio(false);cin.tie(0);
    using namespace std;
     
    typedef long long ll;
    typedef pair<int,int> pii;
    typedef pair<ll , ll> pll;
     
    const int maxn=411111;
    //geaph
    int first[maxn],nxt[maxn],u[maxn],v[maxn];
    int n,m,cnt;
    //dij
    ll dist[maxn],ct[maxn],book[maxn];
    //邻接表
    void add(int x,int y){
        u[++cnt]=x;v[cnt]=y;
        nxt[cnt]=first[u[cnt]];first[u[cnt]]=cnt;
        return;
    }
     
    void Dijkstra(int s){
        CSE(dist,INF);CSE(ct,0);CSE(book,0);
        priority_queue<pii,vector<pii>,greater<pii>> box;
        dist[s]=0;ct[s]=1;box.push(make_pair(0,s));
        while(!box.empty()){
            int x=box.top().second;
            ll d=box.top().first;
            box.pop();
            if(book[x]) continue;
            book[x]=1;
            for(int i=first[x];i!=-1;i=nxt[i]){
                int y=v[i];
                if(dist[y]>d+1){
                    dist[y]=d+1;
                    ct[y]=ct[x];
                    box.push(make_pair(dist[y],y));
                }
                else if(dist[y]==d+1){
                    ct[y]=(ct[y]+ct[x])%100003;
                }
            }
        }
        return;
    }
     
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("in.in","r",stdin);
    #endif
        CSE(first,-1);CSE(nxt,-1);
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        Dijkstra(1);
        for(int i=1;i<=n;i++){
            printf("%lld
    ",ct[i]%100003);
        }
        return 0;
    }
    

    G-最优贸易(cf 1600)

    思路

    本题有点类似于“农场派对”那题,因为要求每条路径上最大权和最小权之差,所以,对于最小权我们修改Dijkstra来计算每条路径上的最小权值(这里要遍历所有路径,所以对于每个顶点我们都要加入队列进行扩展),之后我们将图中的路径方向取反,然后原点改为(n),我用新得到的图计算最大权,两遍Dijkstra之后对于所有节点取每个节点处最大权减最小权的最大值即可(注意判断是否会到达该点)。对于这题可以用SPFA代替Dijkstra,可以有一定优化。

    Code
    /****************************************************
    /@Author: Kirito
    /@TIME:   2020-05-03
    /@FILENAME: businessbest.cpp
    /@REMARK:    
    /****************************************************/
    #include <bits/stdc++.h>
    #define lowbit(x) (x&(-x))
    #define CSE(x,y) memset(x,y,sizeof(x))
    #define INF 0x3f3f3f3f
    #define Abs(x) (x>=0?x:(-x))
    #define FAST ios::sync_with_stdio(false);cin.tie(0);
    using namespace std;
    
    typedef long long ll;
    typedef pair<int,int> pii;
    typedef pair<ll , ll> pll;
    
    const int maxn=1111111;
    //information
    int n,m,city[maxn];
    //graph1
    int head1[maxn],next1[maxn],v1[maxn],cnt1;
    //graph2
    int head2[maxn],next2[maxn],v2[maxn],cnt2;
    //dij
    int dist1[maxn],book1[maxn],dist2[maxn],book2[maxn];
    //邻接表的建立
    void add1(int x,int y){
        v1[++cnt1]=y;
        next1[cnt1]=head1[x];head1[x]=cnt1;
        return;
    }
    
    void add2(int x,int y){
        v2[++cnt2]=y;
        next2[cnt2]=head2[x];head2[x]=cnt2;
        return;
    }
    
    void Dijkstra1(int s){//取最小
        memcpy(dist1,city,sizeof(city));CSE(book1,0);
        priority_queue<pii,vector<pii>,greater<pii>> box;
        box.push(make_pair(dist1[s],s));
        while(!box.empty()){
            int minn=box.top().first;int x=box.top().second;box.pop();
            if(book1[x]) continue;
            book1[x]=1;
            for(int i=head1[x];i!=-1;i=next1[i]){
                int y=v1[i];
                if(dist1[y]>minn) dist1[y]=minn;
                box.push(make_pair(dist1[y],y));
            }
        }
        return;
    }
    
    void Dijkstra2(int s){//取最大
        memcpy(dist2,city,sizeof(city));CSE(book2,0);
        priority_queue<pii,vector<pii>,greater<pii>> box;
        box.push(make_pair(dist2[s],s));
        while(!box.empty()){
            int maxx=box.top().first;int x=box.top().second;box.pop();
            if(book2[x]) continue;
            book2[x]=1;
            for(int i=head2[x];i!=-1;i=next2[i]){
                int y=v2[i];
                if(dist2[y]<maxx) dist2[y]=maxx;
                box.push(make_pair(dist2[y],y));
            }
        }
        return;
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("in.in","r",stdin);
    #endif
        FAST;
        CSE(head1,-1);CSE(head2,-1);CSE(next1,-1);CSE(next2,-1);
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            cin>>city[i];
        }
        for(int i=0;i<m;i++){
            int x,y,z;
            cin>>x>>y>>z;
            add1(x,y);add2(y,x);
            if(z==2){
                add1(y,x);add2(x,y);
            }
        }
        Dijkstra1(1);
        Dijkstra2(n);
        int ans=0;
        for(int i=1;i<=n;i++){
            if(book1[i]&&book2[i]){
                ans=max(ans,dist2[i]-dist1[i]);
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    
  • 相关阅读:
    【Shell】Shell介绍及常用shell脚本
    【Redis】Redis底层数据结构原理--简单动态字符串 链表 字典 跳跃表 整数集合 压缩列表等
    检查Mysql主从状态
    三种方式获取随机字符串或数字
    Intellij 编译时报 未结束的字符串字面值
    IDEA 远程调试
    kafka操作命令
    maven idea设置查找依赖优先从指定的本地仓库获取
    详解布隆过滤器的原理、使用场景和注意事项
    IDEA查找接口实现类及快速实现接口
  • 原文地址:https://www.cnblogs.com/LeafLove/p/12823500.html
Copyright © 2011-2022 走看看