贪心算法--畜栏保留问题(poj3190 )

这篇博客探讨了如何运用贪心算法解决畜栏保留问题。首先将奶牛按开始时间排序,然后从最早开始的奶牛分配畜栏,并依次处理后续奶牛,优先考虑结束时间最早的畜栏。如果现有畜栏的结束时间早于新奶牛的开始时间,奶牛可以直接使用该畜栏,否则分配新的畜栏。为了达到nlogn的时间复杂度,建议使用STL中的优先队列。注意,C++编译器在POJ上的行为可能与g++不同。

畜栏保留问题


总时间限制: 
1000ms 
内存限制: 
65536kB
描述

农场有N头牛,每头牛会在一个特定的时间区间[A, B](包括AB)在畜栏里挤奶,且一个畜栏里同时只能有一头牛在挤奶。现在农场主希望知道最少几个畜栏能满足上述要求,并要求给出每头牛被安排的方案。对于多种可行方案,主要输出一种即可。

输入
输入的第一行包含一个整数N(1 ≤ N ≤ 50, 000),表示有N牛头;接下来N行每行包含两个数,分别表示这头牛的挤奶时间[Ai, Bi](1 ≤ A≤ B ≤ 1, 000, 000)。
输出
输出的第一行包含一个整数,表示最少需要的畜栏数;接下来N行,第i+1行描述了第i头牛所被分配的畜栏编号(从1开始)。
样例输入
5
1 10
2 4
3 6
5 8
4 7
样例输出
4
1
2
3
2
4

这也是一个贪心的算法,在我看来贪心算法,就是平时这么用平常的思维解决问题,在贪心算法中,证明贪心算法我觉得是最难的部分,可是用平时的思维去思考的话,其实,你会发现其实,不用证明好像就是对的;


1) 把所有奶牛按开始时间从小到大排序。
2) 为第一头奶牛分配一个畜栏。
3) 依次处理后面每头奶牛i。处理 i 时,考虑已分配畜栏中,结束时间最早的畜栏x

E(x) < S(i), 则不用分配新畜栏,i可进入x,并修改E(x)E(i)E(x) >= S(i),则分配新畜栏y,E(y) = E(i)

直到所有奶牛处理结束

需要用优先队列存放已经分配的畜栏,并使得结束时间最早的畜栏始终
位于队列头部。

这里第搜索畜栏有没有空的,最好使用STL中的优先队列,这样时间复杂度才是nlogn,这样才能勉强过;

ps:在poj上c++编译能过,g++不能过;

#include<iostream>
#include <queue>

using namespace std;
#define NUM 50005

struct cow{
    int f;
    int e;//挤奶区间起终点
    int NO;//编号
    bool operator<(const struct cow  &t) const{
        return this->f<t.f;
    }
}Cow[NUM];
int result[NUM];//表示编号为i的奶牛去的畜栏编号

struct Fence
{
    int k;//开始
    int j;//结束
    int NO;//栅栏编号;
    bool operator<(const Fence &t)const{
        return this->j>t.j;//先用时间结束晚的;
    }
    Fence(){};
    Fence(int x,int y,int n):k(x),j(y),NO(n){}
};




int main()
{
    int N;
    cin>>N;
    for(int i = 0;i<N;i++)
        {cin>>Cow[i].f>>Cow[i].e;  Cow[i].NO = i;}

//    for(int i = 0;i<N;i++)
//        {cout <<Cow[i].f<<" "<<Cow[i].e<<" "<< Cow[i].NO<<endl;}
    sort(Cow, Cow+N);

//    for(int i = 0;i<N;i++)
//        {cout <<Cow[i].f<<" "<<Cow[i].e<<" "<< Cow[i].NO<<endl;}



    int totle = 0;
    priority_queue<Fence > pq;
    for(int i = 0;i<N;i++){
        if(pq.empty()){
            totle++;
            pq.push(Fence(Cow[i].f,Cow[i].e,totle));
            result[Cow[i].NO] = totle;
        }
        else{
            Fence tt = pq.top();
            if(tt.j<Cow[i].f){
                pq.pop();
                result[Cow[i].NO] = tt.NO;
                pq.push(Fence(Cow[i].f,Cow[i].e,tt.NO));
            }
            else{
                totle++;
                pq.push(Fence(Cow[i].f,Cow[i].e,totle));
                result[Cow[i].NO] = totle;
            }
        }


    }
    cout <<totle<<endl;
    for(int i = 0;i < N;++i)
        cout <<result[i]<<endl;




    return 0;
}


### 畜栏保留问题的算法与编程实现 畜栏保留问题(Stable Marriage Problem 或相关变种问题)通常涉及分配资源或匹配对象的问题。以下是一个基于贪心算法和动态规划思想的解决方案,假设问题的目标是最小化某种代价或最大化某种收益。 #### 问题描述 给定一组畜栏和一组牛,每头牛对每个畜栏有一个偏好值,或者每个畜栏对每头牛有一个接受能力值。目标是将牛分配到畜栏中,使得满足某种条件下的最优解。 #### 解决方案 以下是一个基于排序和贪心策略的实现[^1]: ```python def assign_cows_to_stalls(preferences, k): """ 分配牛到畜栏的函数。 :param preferences: 牛对畜栏的偏好列表,二维数组 :param k: 每个畜栏的最大容量 :return: 分配结果 """ n = len(preferences) # 牛的数量 m = len(preferences[0]) # 畜栏的数量 # 初始化分配状态 stall_assignments = [[] for _ in range(m)] for cow_index, preference in enumerate(preferences): # 对当前牛的偏好进行排序 sorted_stalls = sorted(range(m), key=lambda x: preference[x]) # 尝试将牛分配到最偏好的畜栏 for stall in sorted_stalls: if len(stall_assignments[stall]) < k: stall_assignments[stall].append(cow_index) break return stall_assignments # 示例输入 preferences = [ [3, 1, 2], # 第一头牛对三个畜栏的偏好 [2, 3, 1], [1, 2, 3] ] k = 2 # 每个畜栏最多容纳两头牛 # 调用函数 result = assign_cows_to_stalls(preferences, k) # 输出结果 for i, cows in enumerate(result): print(f"Stall {i + 1} has cows: {cows}") ``` #### 算法说明 上述代码实现了基于偏好排序的分配逻辑。对于每头牛,按照其对畜栏的偏好顺序尝试分配,直到找到一个未满的畜栏为止。如果所有畜栏都已满,则该牛无法被分配。 #### 动态规划思路 如果问题变为需要最小化某种代价(例如分配不均的惩罚),可以使用动态规划解决。以下是动态规划的核心思想[^3]: 1. 定义状态:`dp[i][j]` 表示前 `i` 头牛分配到前 `j` 个畜栏的最小代价。 2. 转移方程:根据当前牛是否分配到某个畜栏更新状态。 3. 初始条件:`dp[0][j] = 0`,表示没有牛时代价为零。 #### 相关公式 动态规划的状态转移方程如下: \[ dp[i][j] = \min(dp[i-1][j], dp[i][j-1] + cost(i, j)) \] 其中,`cost(i, j)` 表示将第 `i` 头牛分配到第 `j` 个畜栏的代价。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值