【usaco 2006 feb gold】 牛棚安排

终于自己独立做出来一道题QAQ然而本校数据实在太水不能确定我是不是写对了。。。

原题:

Farmer John的N(1<=N<=1000)头奶牛分别居住在农场所拥有的B(1<=B<=20)个牛棚的某一个里。有些奶牛很喜欢她们当前住的牛棚,而另一些则讨厌再在它们现在所在的牛棚呆下去。

  FJ在忍受了若干次奶牛的抱怨后,决定为所有奶牛重新安排牛棚,使最不满的那头奶牛与最高兴的奶牛的心情差异最小,即使这会让所有奶牛都更加郁闷。

  每头奶牛都把她对各个牛棚的好感度从高到低排序后告诉了FJ。当然,如果一头奶牛被安排到的牛棚在她给出的列表中越靠后,她就会越郁闷。你可以认为奶牛的郁闷指数是她被分配到的牛棚在列表中的位置。奶牛们是斤斤计较的,她们无法容忍别的奶牛在自己喜欢的牛棚里快乐地生活,而自己却呆在一个自己不喜欢的牛棚里。每个牛棚都只能容纳一定数量的奶牛。FJ希望在每个牛棚都没有超出容量限制的前提下,使最郁闷和最高兴的奶牛的郁闷指数的跨度最小。 

  FJ请你帮他写个程序,来计算这个最小的郁闷指数跨度到底是多少。

刚学网络流来看着道题的时候感觉根本没思路啊,现在再回来看已经能解决掉了(也许是数据实在太水……

要求使最大值与最小值的差最小,有点二分的意思?,因为郁闷值的范围很小(1-n)所以可以枚举最小的,二分最大的

然后根据枚举和二分出的两个值建图,源到每头牛流量1,设a[i][j]为第i头牛郁闷值为j的房间,x为枚举的最小,y为二分的最大,第i头牛就与a[i][x~y]流量为1,每个房间到汇流量为房间容量

然后跑最大流,如果能跑到满流,说明方案合法继续二分

数据太水,不好验证这样做是否正确,应该是正确的吧= =

终于自己做出来一道题了好开心OvO

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<vector>
 7 using namespace std;
 8 const int oo=168430090;
 9 int rd(){int z=0,mk=1;  char ch=getchar();
10     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
11     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
12     return z*mk;
13 }
14 struct ddd{int y,v,re;};  vector <ddd> e[1100];
15 inline void ist(int x,int y,int z){  
16     e[x].push_back((ddd){y,z,e[y].size()});
17     e[y].push_back((ddd){x,0,e[x].size()-1});
18 }
19 int n,m,a[1100][30],b[1100];  int s,t;
20 int ans=oo;
21 int lvl[1100];
22 int q[1100],hd=0;
23 void otmp(int x){
24     cout<<x<<endl;
25     for(int i=0;i<e[s].size();++i)  cout<<s<<"->"<<e[s][i].y<<" "<<e[s][i].v<<endl;
26     for(int i=1;i<=n;++i)for(int j=0;j<e[i].size();++j)if(e[i][j].y>n)
27         cout<<i<<"->"<<e[i][j].y-n<<" "<<e[i][j].v<<endl;
28     for(int i=1;i<=m;++i)for(int j=0;j<e[i].size();++j)if(e[i][j].y==t)
29         cout<<i<<"->"<<t<<" "<<e[i][j].v<<endl;
30 }
31 bool gtlvl(){
32     memset(lvl,0,sizeof(lvl));
33     q[hd=1]=s,lvl[s]=1;
34     int x,sz;
35     for(int k=1;k<=hd;++k){
36         x=q[k],sz=e[x].size();
37         for(int i=0;i<sz;++i)if(e[x][i].v && !lvl[e[x][i].y])
38             lvl[e[x][i].y]=lvl[x]+1,q[++hd]=e[x][i].y;
39     }
40     return lvl[t];
41 }
42 int agmt(int x,int y){
43     if(x==t)  return y;
44     int mxflw=0,flw,sz=e[x].size();
45     for(int i=0;i<sz && mxflw<y;++i)if(lvl[e[x][i].y]==lvl[x]+1)
46         if(flw=agmt(e[x][i].y,min(y-mxflw,e[x][i].v))){
47             mxflw+=flw;
48             e[x][i].v-=flw,e[e[x][i].y][e[x][i].re].v+=flw;
49         }
50     if(!mxflw)  lvl[x]=0;
51     return mxflw;
52 }
53 int dnc(){
54     int bwl=0,flw;
55     while(gtlvl())while(flw=agmt(s,oo)){
56         //otmp(flw);
57         bwl+=flw;
58     }
59     return bwl;
60 }
61 bool chck(int x,int y){
62     for(int i=s;i<=t;++i)  e[i].clear();
63     for(int i=1;i<=m;++i)  ist(i+n,t,b[i]);
64     for(int i=1;i<=n;++i)  ist(s,i,1);
65     for(int i=1;i<=n;++i)for(int j=x;j<=y;++j)
66         ist(i,a[i][j]+n,1);
67     //otmp(y-x+1+1000);
68     return dnc()==n;
69 }
70 int bnrsch(int x){
71     int l=0,r=m-x,md;
72     if(!chck(x,x+r))  return oo;
73     while(l+1<r){
74         md=(l+r)>>1;
75         (chck(x,x+md)?r:l)=md;
76     }
77     return (chck(x,x+l)?l:r)+1;
78 }
79 int main(){//freopen("ddd.in","r",stdin);
80     cin>>n>>m;  s=0,t=n+m+1;
81     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)  a[i][j]=rd();
82     for(int i=1;i<=m;++i)  b[i]=rd();
83     for(int i=1;i<=m;++i)  ans=min(ans,bnrsch(i));
84     cout<<ans<<endl;
85     return 0;
86 }
View Code
原文地址:https://www.cnblogs.com/JSL2018/p/6431367.html