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
原文地址:https://www.cnblogs.com/WHFF521/p/11673802.html