caioj.cn 網路流入門6:牛選牛圈
阿新 • • 發佈:2018-11-25
1120: [視訊]網路流入門6:牛選牛圈
時間限制: 1 Sec 記憶體限制: 128 MB提交: 72 解決: 26
[ 提交][ 狀態][ 討論版]
題目描述
【問題描述】有N(1 <= N <= 1000) 頭牛,B (1 <= B <= 20)個牛圈。
每頭牛對於牛圈都有不同的喜好值(最喜歡為1,最不喜歡為B)。牛圈有一定的容量。
現在分配每頭牛到牛圈去,要求所有牛的最大喜好值與最低喜好值的差值最小。輸出最小的“喜好值差”。
【輸入格式】
第一行N和B
下來N行,每行B個數。表示喜歡的牛圈的序號,按喜歡的程度(遞減)給出,比如第一個給出的牛圈的就是最喜歡,最後一個就是最不喜歡的。
下來B個數,每個數表示牛圈最多容納的牛的數目。
【輸出格式】
輸出最小的“喜好值差”。
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
這一道題的建圖如下:
由原點連線每一頭牛,邊的流量為1,這個不用說了
由牛棚連線終點,流量為牛棚的容量
但是為什麼牛和牛棚之間沒有邊呢?
那是因為如果全部建一次很浪費記憶體和時間,所以只需要在二分判斷時根據x值來建滿足條件的邊
程式碼:
#include<cstdio> #include<cstring> using namespace std; struct node { int x,y,c,next,other; }a[210000]; int len,last[210000],st,ed; inline void ins(int x,int y,int c) { int k1,k2; len++;k1=len; a[len].x=x;a[len].y=y;a[len].c=c; a[len].next=last[x];last[x]=len; len++;k2=len; a[len].x=y;a[len].y=x;a[len].c=0; a[len].next=last[y];last[y]=len; a[k1].other=k2; a[k2].other=k1; } int list[1100],head,tail,h[1100]; inline bool bt_h() { memset(h,0,sizeof(h));h[st]=1; list[1]=st;head=1;tail=2; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k].c>0 && h[y]==0) { h[y]=h[x]+1; list[tail++]=y; } } head++; } if(h[ed]>0)return true; else return false; } inline int mymin(int x,int y) { return x<y?x:y; } int findflow(int x,int f) { if(x==ed)return f; int s=0,t; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k].c>0 && h[y]==(h[x]+1) && s<f) { s+=(t=findflow(y,mymin(a[k].c,f-s))); a[k].c-=t; a[a[k].other].c+=t; } } if(s==0)h[x]=0; return s; } int n,m; int b[1100][31],kk[1100];//b[i][j]表示第i頭牛對j牛棚的喜歡程度,kk表示牛棚能容納的牛的只數 inline int check(int x)//表示這個“喜好值差”能 滿足多少頭牛 { int i,j,ll,rr,s=0; st=n+m+1;ed=n+m+2; //for迴圈列舉頭和尾 //找自己第ll喜歡到第ll+x-1喜歡的牛棚 //保證值≤x for(ll=1;ll<=m-x+1;ll++) { rr=ll+x-1; len=0;memset(last,0,sizeof(last)); for(i=1;i<=n;i++) ins(st,i,1); for(i=n+1;i<=n+m;i++) ins(i,ed,kk[i-n]); for(i=1;i<=n;i++) for(j=1;j<=m;j++) if(b[i][j]>=ll && b[i][j]<=rr)//如果這個牛棚在ll和rr(查詢範圍)之間 ins(i,j+n,1);//就建立一條邊 s=0; while(bt_h()==true) s+=findflow(st,999999999);//查詢流量 if(s==n) break;//如果滿足就不用再找了 } return s; } int main() { int i,j,tt; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=m;j++) { scanf("%d",&tt); b[i][tt]=j; } for(i=1;i<=m;i++) scanf("%d",&kk[i]); int l,r,mid,ans=0; l=0,r=m; while(l<=r) { mid=(l+r)/2; if(check(mid)==n) { r=mid-1; ans=mid; } else { l=mid+1; } } printf("%d\n",ans); return 0; }