[POJ3189]稳定的奶牛分配
时间限制: 1 Sec 内存限制: 64 MB
题目描述
农夫约翰有N(1<=N<=1000)只奶牛,每只奶牛住在B(1<=B<=20)个奶牛棚中的一个。当然,奶牛棚的容量有限。有些奶牛对它现在住的奶牛棚很满意,有些就不太满意了。
农夫约翰想要重新安排这些奶牛,使得奶牛的满意度尽可能相同,尽管有可能这意味者所有的奶牛都不喜欢新分配的奶牛棚。
每只奶牛都按顺序给出她喜欢的奶牛棚。在某个分配方案中,一只奶牛的满意度等于她对她的奶牛棚的评价等级。你的工作是找出一种分配方案使得没有奶牛棚超出它的容量,而且奶牛给分配到的奶牛棚的评价等级的范围(即分配到的等级最高的奶牛棚和等级最低的奶牛棚之间的差值+1)尽可能的小。
附上原文:the size of the range (i.e., one more than the positive difference between the the highest-ranked barn chosen and that lowest-ranked barn chosen) of barn rankings the cows give their assigned barns is as small as possible.
输入
第1行:两个用空格隔开的整数,N和B
第2..N+1行:每一行都有B个用空格隔开的正整数,它们恰好是1到B的一个排列。第i+1行的第一个整数是第i只奶牛的首选牛棚的编号,该行的第二个整数是第i只奶牛的第二选择,等等。
第N+2行:B个用空格隔开的整数,分别表示这B个奶牛棚的容量。这些数的和保证至少为N。
输出
一个整数,被分配到的牛棚等级的最小相对差值。
样例输入
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
样例输出
2
解题报告:
本题考最大流算法
比较奇葩的是这道题还要枚举答案。。
运行流程:
1.枚举答案上界u与下界d(就是奶牛的满意度上界和下界)
2.按照u和d建图
建图方法:
- 1.每个奶牛和每个牛棚代表一个节点
- 2.源点向每头奶牛连边,边权为1 代表这头奶牛只能使用一次
- 3.每头奶牛向这头奶牛选择中满意度在[u,d]之间的牛棚连一条权值为1的边
4.每个牛棚向汇点连一条权值为牛棚容量的边
3.跑最大流
4.判断flow是否等于奶牛数量 如果相等,ans=min(ans,d-u+1);
如果把枚举换成二分答案建图跑得飞快
但是原谅我太懒提供不了二分版本答案(. V . )
接下来是代码
#include
#include
#include
using namespace std;
namespace isap{
const int MAXN=2000;
const int MAXM=1000000;
const int INF=0x7f7f7f7f;
const int INF4BIT=0x7f;
struct Node{
int v,c,nxt,bk;
}nodes[MAXM];
int head[MAXN],e_total;
int n,S,T;
inline void addedge(int a,int b,int c){
e_total++;
nodes[e_total].v=b;
nodes[e_total].c=c;
nodes[e_total].nxt=head[a];
nodes[e_total].bk=e_total+1;
head[a]=e_total;
e_total++;
nodes[e_total].v=a;
nodes[e_total].c=0;
nodes[e_total].nxt=head[b];
nodes[e_total].bk=e_total-1;
head[b]=e_total;
}
bool vis[MAXN];
int d[MAXN],vd[MAXN];
void spfa(int start){
queue<int>que;
que.push(start);
vis[start]=true;
while(!que.empty()){
int u=que.front();
que.pop();
vis[u]=false;
for(int e=head[u];e;e=nodes[e].nxt)
if(d[nodes[e].v]>d[u]+1){
d[nodes[e].v]=d[u]+1;
if(!vis[nodes[e].v]){
vis[nodes[e].v]=true;
que.push(nodes[e].v);
}
}
}
for(int i=1;i<=n;i++)
if(d[i]<=n)vd[d[i]]++;
}
int aug(int u,int augv){
if(u==T)return augv;
int last=augv;
for(int e=head[u];e;e=nodes[e].nxt)
if(nodes[e].c&&d[nodes[e].v]+1==d[u]){
int t=aug(nodes[e].v,min(nodes[e].c,last));
nodes[e].c-=t;
nodes[nodes[e].bk].c+=t;
last-=t;
if(d[S]>=n||!last)return augv-last;
}
if(augv==last){
vd[d[u]]--;
if(!vd[d[u]]){d[S]=n+1;return 0;}
d[u]=n+1;
for(int e=head[u];e;e=nodes[e].nxt)
if(nodes[e].c)d[u]=min(d[u],d[nodes[e].v]+1);
vd[d[u]]++;
}
return augv-last;
}
int sap(){
for(int i=1;i<=n;i++)
d[i]=INF;
d[T]=0;
spfa(T);
int flow=0;
while(d[S]return flow;
}
void clear(){
memset(nodes,0,sizeof nodes);
memset(vis,0,sizeof vis);
memset(head,0,sizeof head);
e_total=0;
memset(vd,0,sizeof vd);
}
}
int n,m;
int inp[1200][30];
int bns[30];
void build(int l,int r){
isap::S=1;
isap::T=isap::S+n+m+1;
isap::n=isap::T;
for(int i=1;i<=n;i++){
isap::addedge(isap::S,isap::S+i,1);
for(int j=l;j<=r;j++)
isap::addedge(isap::S+i,isap::S+n+inp[i][j],1);
}
for(int i=1;i<=m;i++)
isap::addedge(isap::S+n+i,isap::T,bns[i]);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&inp[i][j]);
for(int i=1;i<=m;i++)
scanf("%d",&bns[i]);
int ans=m;
for(int i=1;i<=m;i++)
for(int j=i;j<=m;j++){
if(j-i+1>=ans)continue;
isap::clear();
build(i,j);
int t=isap::sap();
if(t>=n)ans=min(j-i+1,ans);
}
printf("%d\n",ans);
}