poj 3614 dinic/贪心 (涂防晒霜)

来源:互联网 发布:手机淘宝怎么进入微淘 编辑:程序博客网 时间:2024/04/28 17:14

题意:有C个奶牛去晒太阳 (1 <=C <= 2500),每个奶牛各自能够忍受的阳光强度有一个最小值和一个最大值,太大就晒伤了,太小奶牛没感觉。刚开始的阳光的强度非常大,奶牛都承受不住,然后奶牛就得涂抹防晒霜,防晒霜的作用是让阳光照在身上的阳光强度固定为某个值。给出了L种防晒霜中每种的数量和固定的阳光强度。每个奶牛只能抹一瓶防晒霜,最后问能够享受晒太阳的奶牛最多有几个。

思路:一个显然的思路是用最大流来做,牛作为一部,防晒霜作为一部,防晒霜适用于牛则连边,流量为1。防晒霜到汇点流量为该防晒霜的数量,求最大流。

回忆算法课贪心那章的作业第一题:给出n个区间和n个点,问这n个区间能否和n个点一一对应。当时老师讲了一种nlogn的方法,就是区间按照左端点排序,点也排序,然后从左往右扫一遍点,对于每个点,将左端点小于等于该点的区间入堆(堆按照区间右端点比较,且为小顶堆)。此时将堆顶的元素拿出来作为匹配该点的区间,以此类推。如果处理某点时堆为空,那么必然不存在一一对应。这种贪心思想可以通过交换论证来证明。

那么回到这道题发现类似,只不过区间和点的数量并不是同样多的,但是做法是相同的。而且最后进行处理部分的均摊复杂度为O(C+L),整个的复杂度为O(max(ClogC,LlogL))。

最大流思路:

#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <queue>#include <cstdlib>using namespace std;#define clc(s,t) memset(s,t,sizeof(s))#define INF 0x3fffffff#define N 2505int a[N],b[N],num[N],w[N];struct edge{    int y,c,next;}e[N*N*2+N*4];int first[N<<1],top,flag[N<<1],f[N<<1];int n,m;void add(int x,int y,int c){    e[top].y = y;    e[top].c = c;    e[top].next = first[x];    first[x] = top++;}int bfs(int s,int t){    int i,now;    queue<int> q;    q.push(s);    clc(flag, -1);    flag[s] = 0;    while(!q.empty()){        now = q.front();        q.pop();        for(i = first[now];i!=-1;i=e[i].next)            if(flag[e[i].y] == -1 && e[i].c>0){                flag[e[i].y] = flag[now]+1;                if(e[i].y == t)                    return 1;                q.push(e[i].y);            }    }    return 0;}int dfs(int x,int t,int a){    int i,j,res=0;    if(x==t || !a)        return a;    for(i = f[x];i!=-1;i=f[x]=e[i].next)        if(flag[e[i].y] == flag[x]+1){            j = dfs(e[i].y,t,min(a,e[i].c));            if(!j) continue;            res += j;            e[i].c -= j;            e[i^1].c += j;            a -= j;            if(!a) break;        }    return res;}int dinic(int s,int t){    int res = 0;    while(bfs(s,t)){        memcpy(f, first, sizeof(first));        res += dfs(s,t,INF);    }    return res;}int main(){    int i,j;    clc(first,-1);    top = 0;    scanf("%d %d",&n,&m);    for(i = 1;i<=n;i++)        scanf("%d %d",&a[i],&b[i]);    for(i = 1;i<=m;i++)        scanf("%d %d",&w[i],&num[i]);    for(i = 1;i<=n;i++)        for(j = 1;j<=m;j++)            if(w[j]>=a[i] && w[j]<=b[i])                add(i,j+n,1),add(j+n,i,0);    for(i = 1;i<=n;i++)        add(0,i,1),add(i,0,0);    for(i = 1;i<=m;i++)        add(i+n,n+m+1,num[i]),add(n+m+1,i+n,0);    printf("%d\n",dinic(0,n+m+1));    return 0;}

贪心思路:

#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <algorithm>#include <queue>using namespace std;#define INF 0x3fffffff#define clr(s,t) memset(s,t,sizeof(s))#define N 2505struct interval{    int a,b;    bool operator<(const interval x)const{        return x.b < b;    }}s[N];struct line{    int x,num;}t[N];int n,m;priority_queue<struct interval> q;int cmp1(interval x,interval y){    return x.a < y.a;}int cmp2(line a,line b){    return a.x < b.x;}int main(){    int i,j,res=0;    scanf("%d %d",&n,&m);    for(i = 0;i<n;i++)        scanf("%d %d",&s[i].a,&s[i].b);    for(i = 0;i<m;i++)        scanf("%d %d",&t[i].x,&t[i].num);    sort(s,s+n,cmp1);    sort(t,t+m,cmp2);    for(i = j = 0;i<m;i++){        for(;j<n&&s[j].a<=t[i].x;j++)            q.push(s[j]);        while(!q.empty()){//先把肯定不符合的弹出来            if(q.top().b >= t[i].x)                break;            q.pop();        }        while((t[i].num--) && !q.empty()){//这是在堆里的都是必然符合的            q.pop();            res++;        }    }    printf("%d\n",res);    return 0;}


0 0
原创粉丝点击