【贪心+优先队列、网络流】:poj2614,Sunscreen



标准解是贪心:
题解:
贪心即可。
先将翻晒霜按spf值排序,从小到大处理。
对于当前处理的防晒霜,找到能使用它且spf上界最小的牛,将防晒霜供其使用。
因为上界越大,选择越多,在之后可能也可以找到匹配的防晒霜,
而由于从小到大处理,下界已经没有意义(不可能找到比当前spf更小的匹配),这是贪心的原则。 


注意:

 while(k<=c && nodeCow[k].a<=a) //do not add "&& nodeCow[k].b>=a"
 {
	pq.push(nodeCow[k++].b);
 }
否则这个while就可能中断,可以改成:

 while(k<=c && nodeCow[k].a<=a) //do not add "&& nodeCow[k].b>=a"
 {
	if(nodeCow[k].b>=a) //但是会超时,好蛋疼
	{
		pq.push(nodeCow[k++].b);
	}
 }

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;

#define C 2505
#define L 2505

struct NODE
{
    int a,b;
};

NODE nodeCow[C];
NODE nodeSun[L];


int cmp(NODE x, NODE y)
{
    return x.a<y.a;
}

struct lessPQ
{
    bool operator()(int a, int b)
    {
        return a>b;
    }
};

int main()
{
    int c,l,i,j,k,a,b,sum;
    priority_queue<int, vector<int>, lessPQ> pq;

    cin>>c>>l;
    for(i=1;i<=c;i++)
    {
        cin>>nodeCow[i].a>>nodeCow[i].b;
    }
    for(i=1;i<=l;i++)
    {
        cin>>nodeSun[i].a>>nodeSun[i].b;
    }

    sort(nodeCow+1,nodeCow+1+c,cmp);
    sort(nodeSun+1,nodeSun+1+l,cmp);
/*
    for(i=1;i<=c;i++)
    {
        cout<<nodeCow[i].a<<" "<<nodeCow[i].b<<endl;
    }
    for(i=1;i<=l;i++)
    {
        cout<<nodeSun[i].a<<" "<<nodeSun[i].b<<endl;
    }
*/

    sum=0;
    k=1;
    for(i=1;i<=l;i++)
    {
        for(j=1;j<=nodeSun[i].b;j++)
        {
            a=nodeSun[i].a;
            while(k<=c && nodeCow[k].a<=a)
            {
                pq.push(nodeCow[k++].b);
            }
            while(!pq.empty())
            {
                b=pq.top();
                pq.pop();
                //cout<<b<<endl;
                if(b>=a)
                {
                    sum++;
                    break;
                }
            }
        }
    }

    cout<<sum<<endl;

    return 0;
}




网络流解法:

建图:s到每头牛连边,边权为1
每个防晒霜到t连边,边权为使用次数
每头牛到能使用的防晒霜连边,边权为1

/*
 * Dinic algo for max flow
 *
 * This implementation assumes that #nodes, #edges, and capacity on each edge <= INT_MAX,
 * which means INT_MAX is the best approximation of INF on edge capacity.
 * The total amount of max flow computed can be up to LLONG_MAX (not defined in this file),
 * but each 'dfs' call in 'dinic' can return <= INT_MAX flow value.
 */
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <assert.h>
#include <queue>
#include <vector>

# include<iostream>
# include<cstring>
# include<map>
#include<algorithm>

#define C 2505
#define L 2505

#define N (C+L)       //==================make sure this is the total node number!
#define M (N*N+4*N)

typedef long long LL;

using namespace std;

struct edge
{
    int v, cap, next;
};
edge e[M];

int head[N], level[N], cur[N];
int num_of_edges;

//When there are multiple test sets, you need to re-initialize before each
void dinic_init(void)
{
    num_of_edges = 0;
    memset(head, -1, sizeof(head));
    return;
}

int add_edge(int u, int v, int c1, int c2)
{
    int& i=num_of_edges;

    assert(c1>=0 && c2>=0 && c1+c2>=0); // check for possibility of overflow
    e[i].v = v;
    e[i].cap = c1;
    e[i].next = head[u];
    head[u] = i++;

    e[i].v = u;
    e[i].cap = c2;
    e[i].next = head[v];
    head[v] = i++;
    return i;
}

void print_graph(int n)
{
    for (int u=0; u<n; u++)
    {
        printf("%d: ", u);
        for (int i=head[u]; i>=0; i=e[i].next)
        {
            printf("%d(%d)", e[i].v, e[i].cap);
        }
        printf("\n");
    }
    return;
}

//Find all augmentation paths in the current level graph This is the recursive version
int dfs(int u, int t, int bn)
{
    if (u == t) return bn;
    int left = bn;
    for (int i=head[u]; i>=0; i=e[i].next)
    {
        int v = e[i].v;
        int c = e[i].cap;
        if (c > 0 && level[u]+1 == level[v])
        {
            int flow = dfs(v, t, min(left, c));
            if (flow > 0)
            {
                e[i].cap -= flow;
                e[i^1].cap += flow;
                cur[u] = v;
                left -= flow;
                if (!left) break;
            }
        }
    }
    if (left > 0) level[u] = 0;
    return bn - left;
}

bool bfs(int s, int t)
{
    memset(level, 0, sizeof(level));
    level[s] = 1;
    queue<int> q;
    q.push(s);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        if (u == t) return true;
        for (int i=head[u]; i>=0; i=e[i].next)
        {
            int v = e[i].v;
            if (!level[v] && e[i].cap > 0)
            {
                level[v] = level[u]+1;
                q.push(v);
            }
        }
    }
    return false;
}

LL dinic(int s, int t)
{
    LL max_flow = 0;

    while (bfs(s, t))
    {
        memcpy(cur, head, sizeof(head));
        max_flow += dfs(s, t, INT_MAX);
    }
    return max_flow;
}

int upstream(int s, int n)
{
    int cnt = 0;
    vector<bool> visited(n);
    queue<int> q;
    visited[s] = true;
    q.push(s);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i=head[u]; i>=0; i=e[i].next)
        {
            int v = e[i].v;
            if (e[i].cap > 0 && !visited[v])
            {
                visited[v] = true;
                q.push(v);
                cnt++;
            }
        }
    }
    return cnt; // excluding s
}








struct NODE
{
    int a,b;
};

NODE nodeCow[C];

int cmp(NODE x, NODE y)
{
    return x.a<y.a;
}

int main()
{
    int c,l,a,b,i,j;
    dinic_init();
    cin>>c>>l;
    for(i=1;i<=c;i++)
    {
        cin>>nodeCow[i].a>>nodeCow[i].b;
        add_edge(0,i,1,0);
    }
    sort(nodeCow+1,nodeCow+1+c,cmp);

    for(i=1;i<=l;i++)
    {
        cin>>a>>b;
        add_edge(c+i,c+l+1,b,0);
        for(j=1;j<=c;j++)
        {
            if(nodeCow[j].a<=a)
            {
                if(nodeCow[j].b>=a)
                {
                    add_edge(j,c+i,1,0);
                }
            }
            else
            {
                break;
            }
        }
    }

    cout<<dinic(0,c+l+1)<<endl;

    return 0;
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值