zoukankan      html  css  js  c++  java
  • P1986 元旦晚会——贪心或差分约束系统

    P1986 元旦晚会

    每个人可能属于不同的声部,每个声部最少要有c[i]个人发声;

    求最少需要多少话筒;

    首先贪心,将所有声部的区间按照右端点大小排序,如果右端点相同,左端点从小到大排序;

    贪心每次选取靠近右端点的,这样每个区间相交的是最多的。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=130010;
    
    struct node 
    {
        int l,r,c;
    }a[maxn];
    
    bool cmp(node qw,node we)
    {
        if(qw.r!=we.r) return qw.r<we.r;
        return qw.l<we.l;
    }
    
    int n,m;
    int ans,vis[maxn];
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].c);
        }
        
        sort(a+1,a+m+1,cmp);
        
        
        for(int i=1;i<=m;i++)
        {
            int k=0;
            for(int j=a[i].r;j>=a[i].l;j--)
            {
                if(vis[j]) k++;
            }
            
                if(k>=a[i].c) continue;
                else 
                {
                    for(int h=a[i].r;(h>=a[i].r-a[i].c+1)&&(k<a[i].c);h--)
                    {
                        if(!vis[h])
                        {
                            vis[h]=1;
                            ans++;
                            k++;
                        }
                        
                    }
                }
        }
        printf("%d",ans);
        return 0;
    }
    View Code

    差分约束系统:

    将左右端点连边,边权是c[i];因为要保持图的联通,实际连边是x-1和y;

    将i和i-1连一条-1的边,将i和i+1连一条0边;

    跑一边最长路即为所求答案。

    我们所求的实际上是不等式dis[y]-dis[x]>=c[i];

    求最长路时的松弛操作正是将这个不等式一点点的满足;

    为什么要将i和i-1连-1边呢?

    因为可能是这种情况:

    -1其实是将重合的部分减去

    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    using namespace std;
    const int maxn=1e6+10;
    int pre[maxn*2],last[maxn],other[maxn*2],len[maxn*2],l;
    
    void add(int x,int y,int z)
    {
        l++;
        pre[l]=last[x];
        last[x]=l;
        other[l]=y;
        len[l]=z;
    }
    
    queue<int> q;
    int n,m;
    int dis[maxn];
    bool vis[maxn];
    void spfa()
    {
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            vis[x]=0;
            for(int p=last[x];p;p=pre[p])
            {
                int v=other[p];
                if(dis[v]<dis[x]+len[p])
                {
                    dis[v]=dis[x]+len[p];
                    if(!vis[v]) vis[v]=1,q.push(v);
                }
            }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x-1,y,z);
        }
        for(int i=1;i<=n;i++)
        {
            add(i,i-1,-1);
            add(i-1,i,0);
        }
        for(int i=1;i<=n;i++) q.push(i),vis[i]=1;
        spfa();
        printf("%d",dis[n]);
        return 0;
    }
    View Code
  • 相关阅读:
    IDEA、Eclipse快捷键对比
    linux常见命令
    拷贝本地文件到远程服务器的批处理脚本
    关系型数据库的超键、候选键、主键
    JAVA运算符总结
    JAVA原码反码补码
    JPA查询语句(转载)
    Spring Data JPA初使用(转载)
    android学习————项目导入常见错误整理(转载)
    Spring 系列: Spring 框架简介
  • 原文地址:https://www.cnblogs.com/WHFF521/p/11673802.html
Copyright © 2011-2022 走看看