题意大概是,又是一个农民,他有N头牛,B个牛棚。而这些牛对于这些牛棚都有自己的看法,并给出了自己对于这些牛棚的喜爱程度。而每个牛棚呢又都有牛的头数的限制,所以不是所有的牛都选上自己的第一志愿。要求的是志愿数的最大宽度的最小值。。
这里有一个坑。。他要求的是志愿排序的最大宽度的最小值,但并没有说以第一志愿为标准。所以我们都要看一遍。这里就有一个遍历的过程了。
而其他的和之前的二分查找+匹配几乎一样。只是有一条条件不一样了,就是在匹配的时候,我们要求图的那个点的志愿排名大于等于L, 小于等于R。 然后遍历不能写到judge函数里面去,写进去怎样都不太对,我们只有在外层进行遍历,然后一个一个找起点,进行宽度测试。这里就用到了二分的思想了。
int m[len][25];
int vis[len], l[len][len];
int cow[len];//牛棚的最大数
int cnt[len];
int N, B;
int main()
{
while(cin >> N >> B)
{
int num;
for (int i=0; i<N; i++)
{
for (int j=0; j<B; j++)
{
cin >> num;
m[i][num-1] = j;//排序,从0开始所以减一
}
}
for (int i=0; i<B; i++)
cin >> cow[i];
int L=0, R=B, ans, mid, i;
while (L<R)
{
mid = (L + R) / 2;
for (i=0; i<B; i++){
if (judge(i, i+mid)) break;
}//这个循环就是一次遍历,也是枚举
if (i<B)
{
ans = mid;
R = mid;
}
else
{
L = mid + 1;
}
}
// cout << endl;
// for (int i=0; i<N; i++){
// for (int j=0; j<cow[i]; j++){
// cout << l[i][j] << " ";
// }
// cout << endl;
// }
// cout << endl;
cout << ans+1 << endl;
}
return 0;
}
bool judge(int L, int R)
{
memset(cnt, 0, sizeof(cnt));
for (int j=0; j<N; j++)
{
memset(vis, 0, sizeof(vis));
if (!find(j, L, R))
return false;
}
return true;
}
bool find(int p, int L, int R)
{
for (int i=0; i<B; i++)
{
if (m[p][i]>=L && m[p][i]<=R && !vis[i])
{
vis[i] ++;
if (cnt[i]<cow[i])
{
l[i][cnt[i] ++] = p;
return true;
}
else
{
for (int j=0; j<cnt[i]; j++)
{
if (find(l[i][j], L, R))
{
l[i][j] = p;
return true;
}
}
}
}
}
return false;
}