POJ_3189
一开始题意各种理解错,首先输入的那个矩阵第i行第j列的值表示的是奶牛i会第j个中意的牛棚,最后求的range就相当于j的range,至于range是变化的范围,比如j在1、2变化,那么range就应该是2,也就是MAX-MIN+1。
因此我们可以枚举range的下界和上届,然后用二分图多重匹配判断是否有解,当然用网络流判断也可以,不过好像比较慢。在枚举range的时候可以做到O(N),比如现在range是[x,y],如果当前无解那么就扩大上届令y=y+1,如果有解就缩小下届令x=x+1。
#include<stdio.h> #include<string.h> #include<algorithm> #define MAXN 1010 #define MAXB 30 #define INF 0x3f3f3f3f int N, B, yM[MAXB][MAXN], visy[MAXB], num[MAXB], limit[MAXB]; int g[MAXN][MAXB], LOW, HIGH; void init() {int i, j, k;for(i = 0; i < N; i ++)for(j = 0; j < B; j ++)scanf("%d", &g[i][j]), -- g[i][j];for(i = 0; i < B; i ++) scanf("%d", &limit[i]); } int searchpath(int cur) {int i, y, j;for(i = LOW; i <= HIGH; i ++)if(!visy[g[cur][i]]){y = g[cur][i], visy[y] = 1;if(num[y] < limit[y]){yM[y][num[y] ++] = cur; return 1;}for(j = 0; j < num[y]; j ++)if(searchpath(yM[y][j])){yM[y][j] = cur;return 1; }}return 0; } int match() {int i;memset(num, 0, sizeof(num[0]) * B);for(i = 0; i < N; i ++){memset(visy, 0, sizeof(visy[0]) * B);if(!searchpath(i)) return 0;}return 1; } void solve() {int ans = INF;LOW = HIGH = 0;while(HIGH < B){if(!match())++ HIGH;elseans = std::min(ans, HIGH - LOW + 1), ++ LOW;}printf("%d\n", ans); } int main() {while(scanf("%d%d", &N, &B) == 2){init();solve(); }return 0; }