POJ 3614 Sunscreen 最大流、多重匹配、贪心

 
Sunscreen
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 1966 Accepted: 688

Description

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. Cowi has a minimum and maximumSPF rating (1 ≤ minSPFi ≤ 1,000;minSPFimaxSPFi ≤ 1,000) that will work. If theSPF rating is too low, the cow suffers sunburn; if theSPF 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 bottlei with anSPF rating SPFi (1 ≤ SPFi ≤ 1,000). Lotion bottlei can covercoveri 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?

Input

* 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 andmaxSPFi
* Lines C+2..C+L+1: Line i+C+1 describes a sunscreen lotion bottlei with space-separated integers:SPFi and coveri

Output

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

Sample Input

3 2
3 10
2 5
1 5
6 2
4 1

Sample Output

2

Source

 
 
数据弱用网络流水过,Dinic只用了125ms,二分图多重匹配也行。
建图:s到每头牛连边,边权为1
每个防晒霜到t连边,边权为使用次数
每头牛到能使用的防晒霜连边,边权为1
 
 
标准解是贪心:
题解:
贪心即可。
先将翻晒霜按spf值排序,从小到大处理。
对于当前处理的防晒霜,找到能使用它且spf上界最小的牛,将防晒霜供其使用。
因为上界越大,选择越多,在之后可能也可以找到匹配的防晒霜,
而由于从小到大处理,下界已经没有意义(不可能找到比当前spf更小的匹配),这是贪心的原则。
复杂度:O(l*logl+n*l)
转载自
http://blog.163.com/benz_/blog/static/18684203020115612011262/
 
最大流代码:
#include<cstdio>
#include<cstring>
#define N 5005
#define M 2000005
#define inf 999999999
#include<algorithm>
using namespace std;

int n,m,s,t,num,adj[N],dis[N],q[N];
pair<int,int> a[2505];
struct edge
{
	int v,w,pre;
}e[M];
void insert(int u,int v,int w)
{
	e[num]=(edge){v,w,adj[u]};
	adj[u]=num++;
	e[num]=(edge){u,0,adj[v]};//有向图
	adj[v]=num++;
}
int bfs()
{
	int i,x,v,head=0,tail=0;
	memset(dis,0,sizeof(dis));
	dis[s]=1;
	q[++tail]=s;
	while(head!=tail)
	{
		x=q[head=(head+1)%N];
		for(i=adj[x];~i;i=e[i].pre)
			if(e[i].w&&!dis[v=e[i].v])
			{
				dis[v]=dis[x]+1;
				if(v==t)
					return 1;
				q[tail=(tail+1)%N]=v;
			}
	}
	return 0;
}
int dfs(int x,int limit)
{
	if(x==t)
		return limit;
	int i,v,tmp,cost=0;
	for(i=adj[x];~i&&cost<limit;i=e[i].pre)
		if(e[i].w&&dis[x]==dis[v=e[i].v]-1)
		{
			tmp=dfs(v,min(limit-cost,e[i].w));
			if(tmp)
			{
				e[i].w-=tmp;
				e[i^1].w+=tmp;
				cost+=tmp;
			}
			else
				dis[v]=-1;
		}
	return cost;
}
int Dinic()
{
	int ans=0;
	while(bfs())
		ans+=dfs(s,inf);
	return ans;
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		int i,j,u,v;
		memset(adj,-1,sizeof(adj));
		num=0;
		s=0;
		t=m+n+1;
		for(i=1;i<=n;i++)
		{
			scanf("%d%d",&u,&v);
			a[i]=make_pair(u,v);
			insert(s,i,1);
		}
		sort(a+1,a+n+1);
		for(i=1;i<=m;i++)
		{
			scanf("%d%d",&u,&v);
			for(j=1;j<=n;j++)
				if(a[j].first<=u&&u<=a[j].second)
					insert(j,n+i,1);
				else if(a[j].first>u)
					break;
			insert(n+i,t,v);
		}
		printf("%d\n",Dinic());
	}
}

二分图多重匹配:
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

int n,m,f[2505],size[2505];
vector<int> adj[2505],mat[2505];
pair<int,int> a[2505];
int dfs(int x)
{
	int i,j,k,u,v;
	for(i=0;i<adj[x].size();i++)
	{
		u=adj[x][i];
		k=size[u];
		if(!f[u])
		{
			f[u]=1;
			if(mat[u].size()<k)
			{
				mat[u].push_back(x);
				return 1;
			}
			for(j=0;j<mat[u].size();j++)
			{
				v=mat[u][j];
				if(dfs(v))
				{
					mat[u][j]=x;
					return 1;
				}
			}
		}
	}
	return 0;
}
int ok()
{	
	int i,ans=0;
	for(i=1;i<=m;i++)
		mat[i].clear();
	for(i=1;i<=n;i++)
	{
		memset(f,0,sizeof(f));
		if(dfs(i))
			ans++;
	}
	return ans;
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		int i,j,u,v;
		for(i=1;i<=n;i++)
		{
			scanf("%d%d",&u,&v);
			a[i]=make_pair(u,v);
			adj[i].clear();
		}
		sort(a+1,a+n+1);
		for(i=1;i<=m;i++)
		{
			scanf("%d%d",&u,&v);
			size[i]=v;
			for(j=1;j<=n;j++)
				if(a[j].first<=u&&u<=a[j].second)
					adj[j].push_back(i);
				else if(a[j].first>u)
					break;
		}
		printf("%d\n",ok());
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值