zoukankan      html  css  js  c++  java
  • P1986 元旦晚会

    一道可以用各种各样的办法做的(水)

    在这里就介绍两种做法

    题意:

    自己看看吧,很明显的意思,就是求前i个人最少有多少个话筒。

    解法1:差分约束

    (dis[i])表示前(i)个人最少有多少个话筒

    根据题目意思每个人都只能有一个话筒 所以 (dis[i[+1>=dis[i+1] dis[i+1]>=dis[i])

    (a_i)(b_i)至少有(c_i)个 所以 (dis[a_i-1]+c_i>=dis[b_i])

    转换一下跑一遍最长路即可。

    CODE:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<cmath>
    
    #define N 30010
    #define M 5050
    #define INF 214748364
    
    using namespace std;
    
    struct edge {
        int to;
        int from;
        int data;
    }e[N * 2 + 1];
    int head[N],cnt;
    int dis[N],m,n;
    bool vis[N];
    queue<int > q;
    
    inline void add_edge(int x,int y,int z) {
        e[++cnt].from = y;
        e[cnt].data = z;
        e[cnt].to = head[x];
        head[x] = cnt;
    }
    void spfa() {
        for(int i = 1 ; i <= n ; i++) 
        	dis[i] = -19260817;
        dis[1] = 0;
        q.push(1); 
        vis[1] = true;
        while(!q.empty()) {
            int u = q.front(); 
            q.pop(); 
            vis[u] = false;
            for(int i = head[u] ; i ; i = e[i].to) {
                int v = e[i].from;
                if(dis[u] + e[i].data > dis[v]) {
                    dis[v] = dis[u] + e[i].data;
                    if(!vis[v]) {
                        q.push(v); 
                        vis[v] = true;
                    }
                }
            }
        }
    }
    
    int main() {
        //n = read(), m = read();
        scanf("%d%d",&n,&m);
        while(m--) {
            //int l = read(), r = read(), k = read();
            int u , v , w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u - 1 , v , w);
        }
        for(int i = 1 ; i <= n ; i++) {
            add_edge(i - 1 , i , 0);
            add_edge(i , i - 1 , -1);
        }
        spfa();
        printf("%d
    ", dis[n]);
        return 0;
    }
    

    啥,你不想写SPFA。不过没关系,我们还有另一种做法。

    解法2:贪心

    我们可以先按所有声部的右端点排序,再进行从后到前的顺序选取拿话筒的人。很显然,如果我们从后往前选取,就会尽量满足后面人的需求,这样就能达到最小值。

    CODE:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    
    using namespace std;
    const int N = 31000;
    
    struct node {
        int a;
        int b;
        int c;
    }e[N];
    int m,n,ans;
    int vis[N];
    
    inline bool cmp(node x,node y) {
        if(x.b != y.b) 
            return x.b < y.b;
        return x.a < y.a;
    }
    void init() {
        scanf("%d%d",&n,&m);
        for(int i = 1 ; i <= m ; i++)
            scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].c);
    }
    void work() {
        sort(e+1 , e + m + 1 , cmp);
        for(int i = 1 ; i <= m ; i++) {
            int cnt = 0;
            for(int j = e[i].b ; j >= e[i].a ; j--) {
                if(vis[j]) cnt++;
            }
            if(cnt > e[i].c) continue;
            else {
                for(int j = e[i].b ; (j >= e[i].b - e[i].c + 1 && cnt < e[i].c) ; j--) {
                    if(!vis[j]) vis[j] = 1 , cnt++ , ans++;
                }
            }
        }
        printf("%d
    ",ans);
    }
    
    int main() {
        init();
        work();
        return 0;
    }
    
  • 相关阅读:
    Intellij IDEA 打开文件tab数量限制的调整
    Mysql处理中文乱码的问题
    MIT算法导论笔记
    算法导论-排序(一)-插入排序、归并排序
    leetcode题解:Search for a Range (已排序数组范围查找)
    leetcode 题解:Merge Sorted Array(两个已排序数组归并)
    leetcode题解:Construct Binary Tree from Inorder and Postorder Traversal(根据中序和后序遍历构造二叉树)
    leetcode题解:Construct Binary Tree from Preorder and Inorder Traversal (根据前序和中序遍历构造二叉树)
    c++11 std::prev、std::next、std::advance与auto 使用
    (转)指针的引用(*&)与指针的指针(**)
  • 原文地址:https://www.cnblogs.com/Repulser/p/9662853.html
Copyright © 2011-2022 走看看