POJ 3189--Steady Cow Assignment【二分图多重匹配 && 最大流求解 && 枚举 && 经典】

Steady Cow Assignment
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 6023 Accepted: 2078

Description

Farmer John's N (1 <= N <= 1000) cows each reside in one of B (1 <= B <= 20) barns which, of course, have limited capacity. Some cows really like their current barn, and some are not so happy. 

FJ would like to rearrange the cows such that the cows are as equally happy as possible, even if that means all the cows hate their assigned barn. 

Each cow gives FJ the order in which she prefers the barns. A cow's happiness with a particular assignment is her ranking of her barn. Your job is to find an assignment of cows to barns such that no barn's capacity is exceeded and 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.

Input

Line 1: Two space-separated integers, N and B 

Lines 2..N+1: Each line contains B space-separated integers which are exactly 1..B sorted into some order. The first integer on line i+1 is the number of the cow i's top-choice barn, the second integer on that line is the number of the i'th cow's second-choice barn, and so on. 

Line N+2: B space-separated integers, respectively the capacity of the first barn, then the capacity of the second, and so on. The sum of these numbers is guaranteed to be at least N.

Output

Line 1: One integer, the size of the minumum range of barn rankings the cows give their assigned barns, including the endpoints.

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


题意:

有n头牛,m个牛棚,每个牛棚都有一定的容量(就是最多能装多少只牛),然后每只牛对每个牛圈的喜好度不同(就是所有牛圈在每个牛心中都有一个排名),然后要求所有的牛都进猪圈,牛棚在牛心中的排名差计算方法为:所有牛中最大排名和最小排名之差。问最小的排名差。

英语不好太坑了 ,理解错了题意,以测试数据举例:

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

前6行是每头牛对牛棚的排名, 第二行2  3  1  4 代表的是 对第二头牛而言,第二个牛棚排第一,第三个牛棚排第二,第一个牛棚排第三,第四个牛棚排第四。

不是第一个牛棚排第二,第二个牛棚排第三,第三个牛棚排第一,第四个牛棚排第四。这点理解搓个 ,wa了好多遍,英语不好真是要哭了。


解析:这一题其实不难,数据比较小,可以用最大流来写,建图有点麻烦,下面是建图过程:

(1)首先虚拟一个源点,汇点。

(2)源点向每头牛建边, 权值为1,

(3)牛棚向汇点建边,权值为每个牛棚的容量。

(4)枚举牛棚的最差排名和最好排名(即枚举排名差) ,在这个排名之内牛和这个牛棚建边。

看看每种情况判断是否合法(是否满流),取最小值。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define maxn 1200
#define maxm 100005
#define INF 0x3f3f3f3f
using namespace std;
int n, m;

struct node {
    int u, v, cap, flow, next;
};
node edge[maxm];
int head[maxn], cnt;
int cur[maxn];
int dist[maxn], vis[maxn];
int num[maxn];//每个牛棚的容量
int val[1200][25];

void init(){
    cnt = 0;
    memset(head, -1, sizeof(head));
}

void add(int u, int v, int w){
    node E;
    edge[cnt] = {u, v, w, 0, head[u]};
    head[u] = cnt++;
    edge[cnt] = {v, u, 0, 0 ,head[v]};
    head[v] = cnt++;
}

void input(){
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
            scanf("%d", &val[i][j]);
    for(int i = 1; i <= m; ++i){
        scanf("%d", &num[i]);
    }
}

void getmap(int l, int r){
    for(int i = 1; i <= n; ++i)
        add(0, i, 1);
    for(int j = 1; j <= m; ++j)
        add(n + j, n + m + 1, num[j]);
//    for(int i = 1; i <= n; ++i)
//        for(int j = 1; j <= m; ++j)
//        if(val[i][j] >= l && val[i][j] <= r)
//        add(i, j + n, 1);
    for(int i = 1; i <= n; ++i)
        for(int j = l; j <= r; ++j)
        add(i, val[i][j] + n, 1);
}

bool BFS(int st ,int ed){
    queue<int>q;
    memset(vis, 0 ,sizeof(vis));
    memset(dist, -1, sizeof(dist));
    vis[st] = 1;
    dist[st] = 0;
    q.push(st);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        for(int i = head[u]; i != -1; i = edge[i].next){
            node E = edge[i];
            if(!vis[E.v] && E.cap > E.flow){
                vis[E.v] = 1;
                dist[E.v] = dist[u] + 1;
                if(E.v == ed)
                    return true;
                q.push(E.v);
            }
        }
    }
    return false;
}

int DFS(int x, int ed, int a){
    if(x == ed || a == 0)
        return a;
    int flow = 0, f;
    for(int &i = cur[x]; i != -1; i = edge[i].next){
        node &E = edge[i];
        if(dist[E.v] == dist[x] + 1 && (f = DFS(E.v, ed, min(a, E.cap - E.flow))) > 0){
            E.flow += f;
            edge[i ^ 1].flow -= f;
            a -= f;
            flow += f;
            if(a == 0)
                break;
        }
    }
    return flow;
}

int maxflow(int st, int ed){
    int flowsum = 0;
    while(BFS(st,ed)){
        memcpy(cur, head, sizeof(head));
        flowsum += DFS(st, ed, INF);
    }
    return flowsum;
}

int main(){
    while(scanf("%d%d", &n, &m) != EOF){
        input();
        int ans = INF;
        for(int i = 1; i <= m; ++i){//枚举排名的下界
            for(int j = i; j <= m; ++j){//枚举排名的上界
                init();
                getmap(i, j);
                if(maxflow(0, n + m + 1) == n)
                    ans = min(ans, j - i + 1);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值