合唱队形、考场安排

博客内容涉及将含重复数字的数组分成多个排序块以实现整体有序,以及解决考场安排问题,确保无作弊行为。提到的问题是二分图的最小顶点覆盖,需要应用匈牙利算法和Konig算法。作者提供了相关思路和代码,并提醒贪心删除不总是能得到正确结果。
摘要由CSDN通过智能技术生成

1.题目大意:把可能含有重复数字的数组分为尽可能多的块,使得每个块分别进行排序后拼接在一起,能得到整体有序的数值

思路:https://blog.csdn.net/fuxuemingzhu/article/details/82934816

Python代码:

N = int(input())
H = list(map(int,input().split()))
houzhui = [1000000000000] * N
houzhui[-1] = H[-1]
qianzhui = [0] * N
qianzhui[0] = H[0]
for i in range(N-2,-1,-1):
    if H[i] < houzhui[i+1]:
        houzhui[i] = H[i]
    else:
        houzhui[i] = houzhui[i+1]
for i in range(1,N):
    if H[i] > qianzhui[i-1]:
        qianzhui[i] = H[i]
    else:
        qianzhui[i] = qianzhui[i-1]
houzhui.append(0)
qianzhui.insert(0,0)
res = 0
for i in range(N+1):
    if qianzhui[i] <= houzhui[i]:
        res += 1
print(res)

C++代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
const int inf = 0x3f3f3f3f;
typedef long long ll;
ll a[maxn], n, minn[maxn], maxx[maxn];
int main()
{    
    ios::sync_with_stdio(0);
    cin>>n;
    for(ll i=1; i<=n; i++)
    cin>>a[i];
    minn[n] = a[n];
    for(ll i=n-1; i>=1; i--)
    minn[i] = min(minn[i+1], a[i]);
    maxx[1] = a[1];
    for(ll i=2; i<=n; i++)
    maxx[i] = max(maxx[i-1], a[i]);
    ll ans = 1;
    for(ll i=2; i<=n; i++)
    if(maxx[i-1] <= minn[i]) ans++;
    cout<<ans<<endl;
    return 0;
}

2.考场安排

原题大意:

作者:材料坑坑坑
链接:https://www.nowcoder.com/discuss/232864?toCommentId=3666270
来源:牛客网
第一行输入两个数n m 

n代表了男生和女生的人数 其中男生序号[1, n] 女生 [n+1, 2n] 

m代表了接下来输入的行数 

每行输入两个数 第一个代表了男生的序号 第二个代表了女生的序号 表示该男生和女生之间会在考试的时候作弊 

我们最少把多少人踢出考场才能保证考场上的人不存在作弊行为 输出这个最小值 并且把踢出的人的序号按照升序排序输出

 

--------------------------

实际上是二分图最小顶点覆盖问题,主要用到了匈牙利算法、Konig算法,不了解的可以去查一下。

不是考试做的,所以不太好测是不是AC,欢迎讨论?

 

另附 最优打印策略(大小写切换)和合唱团分组问题的题解:https://www.nowcoder.com/discuss/232706

 

P.S. 贪心删除得到的不一定是正确结果,比如下面代码中的样例就是一个反例。

"""
Bipartite graph problem
minimum vertex cover == maximum matching (Konig algorithm)
find maximum matching (Hungarian algorithm)
"""
 
 
class BiGraph(object):
    def __init__(self, vx, vy, edges):
        # vx, vy := the two vertex sets of the bipartite graph
        # edges := edge set
        self.vx = vx
        self.vy = vy
        self.edges = edges
 
    def isConnect(self, u, v):
        return (v, u) in self.edges or (u, v) in self.edges
 
    def maxMatching(self):
        # Hungarian algorithm
 
        # init match set M
        res = 0
        Mx = {}
        My = {}
 
        for v in self.vx:
            if v not in Mx:
                res += self.augmentPath(Mx, My, v, set())
 
        return res, Mx, My
 
    def augmentPath(self, Mx, My, v, visited):
 
        for u in self.vy:
            if self.isConnect(u, v) and u not in visited:
                visited.add(u)
 
                if u not in My or self.augmentPath(Mx, My, My[u], visited):
                    Mx[v] = u
                    My[u] = v
                    return True
 
        return False
 
    def minVertexCover(self, Mx, My):
        # Konig algorithm
         
        minCover = self.vx
        # init non matched vx
        stack = [v for v in self.vx if v not in Mx]
        visited = set()
 
        while stack:
            v = stack.pop()
            visited.add(v)
 
            if v in self.vx:
                minCover.remove(v)
                for u in self.vy:
                    if self.isConnect(u, v) and u not in visited:
                        visited.add(u)
                        minCover.add(u)
                        if My[u] not in visited:
                            stack.append(My[u])
 
        return minCover
 
 
if __name__ == '__main__':
    boys = {1, 2, 3, 4}
    girls = {5, 6, 7}
    edges = {(1, 5), (2, 5), (2, 6), (2, 7), (3, 6), (4, 7)}
 
    graph = BiGraph(boys, girls, edges)
 
    res, Mx, My = graph.maxMatching()
    minCover = graph.minVertexCover(Mx, My)
 
    remove_list = sorted(list(minCover))
    print(res, remove_list)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值