洛谷 P2887 [USACO07NOV]防晒霜Sunscreen 解题报告

与世无争的帅哥 提交于 2021-02-02 06:11:30

P2887 [USACO07NOV]防晒霜Sunscreen

题目描述

To avoid unsightly burns while tanning, each of the C (1 ≤ C ≤ 2500) cows must cover her hide with sunscreen when they're at the beach. Cow i has a minimum and maximum SPF rating (1 ≤ minSPFi ≤ 1,000; minSPFi ≤ maxSPFi ≤ 1,000) that will work. If the SPF rating is too low, the cow suffers sunburn; if the SPF rating is too high, the cow doesn't tan at all........

The cows have a picnic basket with L (1 ≤ L ≤ 2500) bottles of sunscreen lotion, each bottle i with an SPF rating SPFi (1 ≤ SPFi ≤ 1,000). Lotion bottle i can cover coveri cows with lotion. A cow may lotion from only one bottle.

What is the maximum number of cows that can protect themselves while tanning given the available lotions?

有$C$个奶牛去晒太阳 (1 <=$C$ <= 2500),每个奶牛各自能够忍受的阳光强度有一个最小值和一个最大值,太大就晒伤了,太小奶牛没感觉。

而刚开始的阳光的强度非常大,奶牛都承受不住,然后奶牛就得涂抹防晒霜,防晒霜的作用是让阳光照在身上的阳光强度固定为某个值。

那么为了不让奶牛烫伤,又不会没有效果。

给出了$L$种防晒霜。每种的数量和固定的阳光强度也给出来了

每个奶牛只能抹一瓶防晒霜,最后问能够享受晒太阳的奶牛有几个。

输入输出格式

输入格式:

  • Line 1: Two space-separated integers: $C$ and $L$

  • Lines 2..$C+1$: Line i describes cow i's lotion requires with two integers: $minSPFi$ and $maxSPFi$

  • Lines $C+2$..$C+L+1$: Line $i+C+1$ describes a sunscreen lotion bottle $i$ with space-separated integers: $SPFi$ and $coveri$

输出格式:

A single line with an integer that is the maximum number of cows that can be protected while tanning


$DINIC$周常写爆:(1/1)

思路:s连每头牛边1,每头牛连合法的防晒霜边1,防晒霜连t使用次数,跑最大流即可。(此题也有别的解法)

前后代码对比: 54分:

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int min(int x,int y){return x<y?x:y;}
const int N=2508;
const int inf=0x3f3f3f3f;
int C,L,l[N],r[N],T;
struct Edge
{
    int next,to,w;
}edge[N*N];
int head[N<<2],cnt=-1;
void add(int u,int v,int w)
{
    edge[++cnt].next=head[u];edge[cnt].to=v;edge[cnt].w=w;head[u]=cnt;
}
int dep[N<<2],s[N<<2],pre[N<<2],used[N<<2],tot=0,ans=0;
queue <int > q;
void push(int x){s[++tot]=x;}
void pop(){tot--;}
bool bfs()
{
    memset(dep,0,sizeof(dep));
    while(!q.empty()) q.pop();
    q.push(0);
    dep[0]=1;
    while(!q.empty()&&q.front()!=T)
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to,w=edge[i].w;
            if(!dep[v]&&w)
            {
                dep[v]=dep[u]+1;
                q.push(v);
            }
        }
    }
    return !q.empty();
}
int main()
{
    scanf("%d%d",&C,&L);
    memset(head,-1,sizeof(head));
    T=C+L+1;
    for(int i=1;i<=C;i++)
    {
        scanf("%d%d",l+i,r+i);
        add(0,i,1),add(i,0,0);
    }
    int num,d;
    for(int i=1;i<=L;i++)
    {
        scanf("%d%d",&d,&num);
        for(int j=1;j<=C;j++)
            if(l[j]<=d&&d<=r[j])
                add(j,i+C,1),add(i+C,j,0);
        add(i+C,T,num),add(T,i+C,0);
    }
    while(bfs())
    {
        push(0);
        memset(used,0,sizeof(used));
        memset(pre,0,sizeof(pre));
        while(tot)
        {
            if(s[tot]==T)
            {
                int now=tot,id,m_min=inf;
                while(pre[s[now]])
                {
                    if(m_min>=edge[pre[s[now]]].w)
                    {
                        m_min=edge[pre[s[now]]].w;
                        id=now-1;
                    }
                    now--;
                }
                ans+=m_min;now=tot;
                while(pre[s[now]])
                {
                    edge[pre[s[now]]].w-=m_min;
                    edge[pre[s[now]]^1].w+=m_min;
                    now--;
                }
                tot=id;
                used[T]=0;
            }
            else
            {
                int u=s[tot];
                for(int i=head[u];i!=-1;i=edge[i].next)
                {
                    int v=edge[i].to,w=edge[i].w;
                    if(!used[v]&&dep[v]==dep[u]+1&&w)
                    {
                        push(v);
                        pre[v]=i;
                        used[v]=1;
                        break;
                    }
                }
                if(s[tot]==u) pop();
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

100分:

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int min(int x,int y){return x<y?x:y;}
const int N=2508;
const int inf=0x3f3f3f3f;
int C,L,l[N],r[N],T;
struct Edge
{
    int next,to,w;
}edge[N*N];
int head[N<<2],cnt=-1;
void add(int u,int v,int w)
{
    edge[++cnt].next=head[u];edge[cnt].to=v;edge[cnt].w=w;head[u]=cnt;
}
int dep[N<<2],s[N<<2],pre[N<<2],used[N<<2],tot=0,ans=0;
queue <int > q;
void push(int x){s[++tot]=x;}
void pop(){tot--;}
bool bfs()
{
    memset(dep,0,sizeof(dep));
    while(!q.empty()) q.pop();
    q.push(0);
    dep[0]=1;
    while(!q.empty()&&q.front()!=T)
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to,w=edge[i].w;
            if(!dep[v]&&w)
            {
                dep[v]=dep[u]+1;
                q.push(v);
            }
        }
    }
    return !q.empty();
}
int main()
{
    scanf("%d%d",&C,&L);
    memset(head,-1,sizeof(head));
    T=C+L+1;
    for(int i=1;i<=C;i++)
    {
        scanf("%d%d",l+i,r+i);
        add(0,i,1),add(i,0,0);
    }
    int num,d;
    for(int i=1;i<=L;i++)
    {
        scanf("%d%d",&d,&num);
        for(int j=1;j<=C;j++)
            if(l[j]<=d&&d<=r[j])
                add(j,i+C,1),add(i+C,j,0);
        add(i+C,T,num),add(T,i+C,0);
    }
    while(bfs())
    {
        push(0);
        memset(used,0,sizeof(used));
        memset(pre,-1,sizeof(pre));
        while(tot)
        {
            if(s[tot]==T)
            {
                int now=tot,id,m_min=inf;
                while(pre[s[now]]!=-1)
                {
                    if(m_min>=edge[pre[s[now]]].w)
                    {
                        m_min=edge[pre[s[now]]].w;
                        id=now-1;
                    }
                    now--;
                }
                ans+=m_min;now=tot;
                while(pre[s[now]]!=-1)
                {
                    edge[pre[s[now]]].w-=m_min;
                    edge[pre[s[now]]^1].w+=m_min;
                    now--;
                }
                tot=id;
                used[T]=0;
            }
            else
            {
                int u=s[tot];
                for(int i=head[u];i!=-1;i=edge[i].next)
                {
                    int v=edge[i].to,w=edge[i].w;
                    if(!used[v]&&dep[v]==dep[u]+1&&w)
                    {
                        push(v);
                        pre[v]=i;
                        used[v]=1;
                        break;
                    }
                }
                if(s[tot]==u) pop();
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

0和-1的锅。。。


2018.6.8

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!