NKOI 1513 稳定的奶牛分配

稳定的奶牛分配

Time Limit:10000MS  Memory Limit:65536K
Total Submit:53 Accepted:23 
Case Time Limit:1000MS

Description

农夫约翰有N(1<=N<=1000)只奶牛,每只奶牛住在B(1<=B<=20)个奶牛棚中的一个。当然,奶牛棚的容量有限。有些奶牛对它现在住的奶牛棚很满意,有些就不太满意了。 

农夫约翰想要重新安排这些奶牛,使得奶牛的满意度尽可能相同,尽管有可能这意味者所有的奶牛都不喜欢新分配的奶牛棚。 

每只奶牛都按顺序给出她喜欢的奶牛棚。在某个分配方案中,一只奶牛的满意度等于她对她的奶牛棚的评价等级。你的工作是找出一种分配方案使得没有奶牛棚超出它的容量,而且奶牛给分配到的奶牛棚的评价等级的相对范围(即分配到的等级最高的奶牛棚和等级最低的奶牛棚之间的差值)尽可能的小。 


Input

第1行:两个用空格隔开的整数,N和B 
第2..N+1行:每一行都有B个用空格隔开的正整数,它们恰好是1到B的一个排列。第i+1行的第一个整数是第i只奶牛的首选牛棚的编号,该行的第二个整数是第i只奶牛的第二选择,等等。 
第N+2行:B个用空格隔开的整数,分别表示这B个奶牛棚的容量。这些数的和保证至少为N。 

Output

一个整数,被分配到的牛棚等级的最小相对差值,输出得到该相对差时所包含的不同等级的牛棚个数。 

Sample Input

6 4
1 2 3 4
2 3 1 4
4 2 3 1
3 1 2 4
1 3 4 2
1 4 2 3
2 1 3 2

Sample Output

2

Hint

每个奶牛都被安排在它的第一选择或第二选择:1号牛棚安排1号奶牛和5号奶牛,2号牛棚安排2号奶牛,3号牛棚安排4号奶牛,4号牛棚安排3号奶牛和6号奶牛。 

输出样例 
表示得到最小相对差为1,这时奶牛们入住进了两种不同等级的牛棚

Source

网络流 usaco feb06 gold


这道题我们很容易就能想到构图的方法:

源点连接每一个奶牛,权值为1,每一个奶牛连接每一个牛棚,权值为1,牛棚连接汇点,权值为牛棚容量。

那么我们怎么得到答案呢?

首先先枚举答案(这里可以用二分也可以直接循环枚举),然后再枚举牛棚的最高等级(我们设1为最高等级)

最后对于每一个枚举的对象跑一次SAP就可以了

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int inf=1e9,maxn=2005;
int n,b,op,ed,M=2,p[maxn],cow[maxn][maxn],g[maxn][maxn];
int dis[maxn],vd[maxn];
void _read(int &xx){
    char tt=getchar();
    while(tt>'9'||tt<'0')tt=getchar();
    for(xx=0;tt>='0'&&tt<='9';tt=getchar())xx=xx*10+(tt-'0');
}
int dfs(int u,int flow){
	if(u==ed)return flow;
	int v,temp,delta=0;
	for(v=1;v<=ed;v++)
		if(g[u][v]&&dis[u]==dis[v]+1){
			temp=dfs(v,min(flow-delta,g[u][v]));
			g[u][v]-=temp;
			g[v][u]+=temp;
			delta+=temp;
			if(delta==flow||dis[op]>=ed)return delta;
		}
	if(dis[op]>=ed)return delta;
	vd[dis[u]]--;
	if(vd[dis[u]]==0)dis[op]=ed;
	dis[u]++;
	vd[dis[u]]++;
	return delta;
}
int main(){
    int i,j,k,ans;
    scanf("%d%d",&n,&b);
    op=n+b+1,ed=op+1;
    for(i=1;i<=n;i++)
        for(j=1;j<=b;j++)
		    _read(cow[i][j]);
    for(i=1;i<=b;i++)_read(p[i]);
    for(ans=0;ans<b;ans++)
        for(k=1;k+ans<=b;k++){
        	int t=0;
            memset(g,0,sizeof(g));
            memset(dis,0,sizeof(dis));
            for(i=1;i<=n;i++)g[op][i]++;
            for(i=1;i<=b;i++)g[i+n][ed]+=p[i];
            for(i=1;i<=n;i++)
			    for(j=k;j<=k+ans;j++)
				    g[i][cow[i][j]+n]++;
            while(dis[op]<ed)t+=dfs(op,inf);
            if(t==n){
                cout<<ans+1;
                return 0;
            }
        }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值