Kick Start 2018 Round E - Problem B Milk Tea

一、 题目描述

  点奶茶时可以选择不同的小料选项: “加冰/不加冰”,“加糖/不加糖”,“加珍珠/不加珍珠”,“加布丁/不加布丁”,等等。我们用零一串来表示顾客的偏好,如果用上面的四个选项,那么 string 1100 表示 “加冰、加糖、不要珍珠、不要布丁”。
  小明要给他的N个朋友每人买杯奶茶。奶茶店给出的小料选择项有P项。N个朋友每人给出了其个人的偏好。但是小明觉得给每个人买不同的实在是太麻烦了,于是他打算只买一种奶茶。每当一个个偏好没有被满足时,他的朋友会抱怨一次。比如:两个朋友的偏好分别是 101 和 010,小明买了 001,那么第一个朋友会抱怨1次,第二个朋友会抱怨2次,总共有3次抱怨。
  除此之外,还给出了M个零一串,表示奶茶店不提供的奶茶类型,小明不能买这些类型。比如,奶茶店可能不愿意提供“加冰”、“热饮”这类奶茶。
  小明能得到的最小抱怨数是多少?

1. 输入

  • T:表示共有T个用例来进行测试
  • 对于每一个例子:
    – 第一行:N、M、P
    – 接下来有N行:每行一个string(由0/1组成),表示每个朋友的要求
    – 接下来有M行:每行一个string(由0/1组成),表示奶茶店不能做的搭配

2. 输出

  每个测试用例输出一行 Case #x: y
   ·x:第x个用例(从1开始)
   ·y:可以获得的最小的抱怨数

3. Limits

  • 1 ≤ T ≤ 100.
  • Time limit: 30 seconds per test case.
  • Memory limit: 1 GB.
  • All of the forbidden types of milk tea are different.

Small dataset (Test set 1 - Visible)

  • 1 ≤ N ≤ 10.
  • 1 ≤ M ≤ min(10, 2P - 1).
  • 1 ≤ P ≤ 10.

Large dataset (Test set 2 - Hidden)

  • 1 ≤ N ≤ 100.
  • 1 ≤ M ≤ min(100, 2P - 1).
  • 1 ≤ P ≤ 100.

二、 解题思路

  如果没有M个被禁止掉的组合,我们只需要对P种选项的每一个做投票,选择多数人选择的那个就可以了。现在有M个被禁止的组合,如果我们手中有 (M+1) 种列出的组合,那也必定有最终能被实现的组合。
  于是问题转化成求最优的前 ( M + 1 ) (M+1) (M+1) 种组合。下面证明:如果 c h o i c e [ 0 , 1 , . . . , p ] choice[0, 1, ..., p] choice[0,1,...,p] 在前 (M+1) 个之内,那么 c h o i c e [ 0 , 1 , . . . , p − 1 ] choice[0, 1, ..., p-1] choice[0,1,...,p1] 一定也在前 (M+1) 个之内。

证明: 假设 choice[0, 1, ..., p] 是前 (M+1) 个,而 choice[0, 1, ..., p-1] 不是前 (M+1) 个;
       设 choice[p] 增加的抱怨数为x;
       那么对 choice[0, 1, ..., p-1] 以及排在其之前的 choice' [0, 1, ..., p-1] 都增加 choice[p];
       必有 choice[0, 1, ..., p] 排在所有的 choice' [0, 1, ..., p] 之后;
       由假设得,choice' 至少有 M+1 个;
       那么 choice[0, 1, ..., p] 必不在前 (M+1) 个之内,
       与假设矛盾,则假设不成立。

  得到了上面的结论之后,我们就能够以 O ( 1 ) O(1) O(1) 的复杂度由 c h o i c e [ 0 , 1 , . . . , p − 1 ] choice[0, 1, ..., p-1] choice[0,1,...,p1] 来得到 c h o i c e [ 0 , 1 , . . . , p ] choice[0, 1, ..., p] choice[0,1,...,p].

三、 代码描述

#include <vector>
#include <string>
#include <algorithm>
#include <iostream>

using namespace std;


class CChoice{
public:
	string c_str;
	int c_cost;

	bool operator <(const CChoice &other) const{
		return c_cost < other.c_cost;
	}
};

int solve(int N, int M, int P, vector<string> &Y, vector<int>agree){
	class CChoice Choice;
	vector<class CChoice> best;
	
	// 初始化best
	Choice.c_str = '0';
    Choice.c_cost = agree[0];
    best.push_back(Choice);
    Choice.c_str = '1';
    Choice.c_cost = N- agree[0];
    best.push_back(Choice);
    
    // 主体部分
    for(int i = 1; i < P; i++){
        vector<class CChoice> cur;
		for(int j = 0; j < best.size(); j++){
            Choice.c_str = best[j].c_str+'0';
            Choice.c_cost = best[j].c_cost+agree[i];
			cur.push_back(Choice);

			Choice.c_str = best[j].c_str+'1';
            Choice.c_cost = best[j].c_cost+N-agree[i];
			cur.push_back(Choice);
		}
		sort(cur.begin(), cur.end());
		//这里保留前2M个最优,主要是担心出现大量cost值即抱怨数相同的情况
		best.assign(cur.begin(), min(cur.begin()+M+M, cur.end()));
    }

    for(int i = 0; i < best.size(); i++){
        for(int j = 0; j < M; j++){
            if(best[i].c_str == Y[j])
                break;
            if(j == (M-1))
                return best[i].c_cost;
        }
    }
}



int main(){
    int T, N, M, P, res;
    cin >> T;

    for(int i = 1; i <= T; i++){
        // 数据输入
        cin >> N >> M >> P;
        vector<string> X(N), Y(M);
        for(int j = 0; j < N; j++)
            cin >> X[j];
        for(int j = 0; j < M; j++)
            cin >> Y[j];

        // 遍历需求矩阵
        vector<int> agree(P);
        for(int j = 0; j < P; j++){
            for(int k = 0; k < N; k++)
                agree[j] += X[k][j]-48;
        }
        
        res = solve(N, M, P, Y, agree);
        cout << "Case #" << i << ": " << res << endl;
    }
    
    return 0;
}
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值