博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[BOI2019][第K大问题][暴力剪枝]D2T1 Olympiads
阅读量:6086 次
发布时间:2019-06-20

本文共 3292 字,大约阅读时间需要 10 分钟。

目录

题意

\(N\)个人,现在你要从中选出\(K\)个人出来,然后让这\(K\)个人一起参加\(K\)场比赛。其中,每个人都要参加所有的比赛。

定义其中一场比赛的得分为这\(K\)个人的得分的最大值。然后定义这个队的得分为\(K\)场比赛的得分的加和。

例如,\(K=3\)时,有一支3个人的队伍,一共打3场比赛。第1个人在3场比赛中的得分分别为\((4, 5, 3)\),第2个人在3场比赛中的得分分别为 \((7, 3, 6)\), 第3个人在3场比赛中的得分分别为 \((3, 4, 5)\)。那么这个队伍的总得分就是\(7+5+6=18\)

现在你要求出的是,总分最第\(C\)大的队伍的得分是多少。定义两个队伍不同,当且仅当存在两个两个队伍的人的编号不同。

输入格式

第一行3个整数分别表示\(N,K,C\)

接下来N行,每行K个整数,表示每个人在每场比赛中的得分。

输出格式

一行,输出得分第\(C\)大的队伍的得分。

样例

Input

5 4 4

7 0 4 9
3 0 8 4
1 1 3 7
5 1 3 4
4 2 2 9

Output

24

数据范围

1.(13 points) 1 ≤ N ≤ 500, 1 ≤ K ≤ 2, 1 ≤ C ≤ 2 000.

2.(31 points) 1 ≤ N ≤ 40, 1 ≤ K ≤ 6, 1 ≤ C ≤ 2 000.
3.(24 points) 1 ≤ N ≤ 500, 1 ≤ K ≤ 6, 1 ≤ C ≤ 2 000, 每个人的分数大小不超过10.
4.(32 points) 1 ≤ N ≤ 500, 1 ≤ K ≤ 6, 1 ≤ C ≤ 2 000.

时间限制

\(2\ sec / 30\ sec\)

思路

首先声明这是自己的方法,没有看官方题解...

首先求一个得分最大的队伍出来,怎么求呢?

就是让每一场比赛的得分都尽量大,也就是取所有人中这场比赛得分最大的那个人。然后这样子选完之后可能没有选齐K个人,那么剩余的位置就随便找人来补齐就好了。

然后仿照所有的求第k大的题目的做法,把这个队伍塞到一个大根堆(priority_queue)中去,每次都从队首取出一个当前的最大答案,然后用这个队伍进行拓展,塞入其它没有出现过的其他队伍。

如何拓展呢?

最暴力的想法是,每次都将这个队伍中的一个人换成另外一个人,然后在确定了这支新的队伍没有出现过之后,就将这支队伍也塞到优先队列中去。

如何判断之前是否重复呢?我用的是Hash,然后把Hash值塞到一个set里面去,就可以简单的判重了。

考虑一下时间复杂度:一共要取出C次,就是\(O(C)\),每次都要枚举将哪个人替换掉,也就是\(O(K)\)。还要枚举替换成哪个人,也就是\(O(N)\)。替换了之后,还要算出新的队伍的得分是多少,也就是\(O(K^2)\)的。然后还有set和priority_queue的时间复杂度,设为\(Const\)。那么总的时间复杂度就是\(O(N*K^3*C*Const)\),大概有\(216,000,000+\),好像跑不过...

考虑剪枝。考虑替换一个人的时候,只在N个人当中选出那些替换之后会使得答案变小或不变的那些人进行判重,判断没有出现过之后再选取其中的最大值进行扩展。这样子总共扩展出来的节点数就有原来的\(C*K*N\)变为了\(C*K\),优先队列和set部分的时间就变小了。然后枚举的时候,也被剪掉了不少。这样子就可以跑到0.3s~0.4s左右。

代码

实现的有点丑,但是算法还是很简单暴力的。

#include
#include
#include
#include
#define MAXN 500#define MAXK 6#define MAXC 2000#define MO 10000007using namespace std;typedef long long LL;struct state{ int val;LL st; state(){}; state(int _val,LL _st):val(_val),st(_st){};};bool operator < (const state &A,const state &B){return A.val
que;struct node{ LL x; node *nxt;}nd[MAXC*MAXN*MAXK+5];node *ncnt=&nd[0],*Adj[MO+5];int n,k,c,tmp[MAXK+1];int scr[MAXN+5][MAXK+1];LL Encode(int *seq){ LL ret=0; for(int i=1;i<=k;i++) ret=1LL*ret*n+(1LL*seq[i]-1); return ret;}void Decode(LL val,int *seq){ for(int i=k;i>=1;i--) seq[i]=val%n+1,val/=n;}int GetVal(int *seq){ int ret=0; for(int j=1;j<=k;j++) { int mxval=0; for(int i=1;i<=k;i++) mxval=max(mxval,scr[seq[i]][j]); ret+=mxval; } return ret;}void Print(int *seq){ for(int i=1;i<=k;i++) printf("%d ",seq[i]); printf("\n");}void Insert(LL x){ int id=x%MO; node *p=++ncnt; p->x=x; p->nxt=Adj[id]; Adj[id]=p;}bool Find(LL x){ int id=x%MO; for(node *p=Adj[id];p!=NULL;p=p->nxt) if(p->x==x) return true; return false;}int Solve(){ static int tmp1[MAXK+5],tmp2[MAXK+5]; static bool sp[MAXN+5]; state fro; for(int tmn=1;tmn
fro.val) continue; if(val>mxval) { sort(tmp2+1,tmp2+1+k); LL st=Encode(tmp2); if(Find(st)) continue; mxval=val,mxst=st; } } if(mxval==-1) continue; Insert(mxst); Decode(mxst,tmp2); que.push(state(mxval,mxst)); } for(int i=1;i<=k;i++) sp[tmp1[i]]=0; } return que.top().val;}int main(){ freopen("olymp.in","r",stdin); freopen("olymp.out","w",stdout); scanf("%d %d %d",&n,&k,&c); for(int i=1;i<=n;i++) for(int j=1;j<=k;j++) scanf("%d",&scr[i][j]); for(int j=1;j<=k;j++) { int mxpos=-1; for(int i=1;i<=n;i++) if(mxpos==-1||scr[mxpos][j]

转载于:https://www.cnblogs.com/T-Y-P-E/p/11046377.html

你可能感兴趣的文章
ABP理论学习之Web API控制器(新增)
查看>>
栈的应用之判断括号匹配
查看>>
让工具类不可实例化
查看>>
EntityFramework Core 1.1是如何创建DbContext实例的呢?
查看>>
iOS开发-NSPredicate
查看>>
MVC模式与struts框架
查看>>
Linux系统的中断、系统调用和调度概述【转】
查看>>
人月神话-人月:项目滞后的原因分析
查看>>
linux驱动学习(二) Makefile高级【转】
查看>>
通过QC远程运行QTP脚本,QTP自动崩溃关闭的解决方法
查看>>
WinServer2012 R2忘记密码的解决方案+远程连接另一种莫名其妙故障
查看>>
linux的mtd架构分析【转】
查看>>
字符串反转问题
查看>>
KMP
查看>>
Mysql占用过高CPU时的优化手段
查看>>
android 布局文件 ScrollView 中的 listView item 显示不全解决方案
查看>>
怎么清理win7、win8更新垃圾(winsxs目录清理)
查看>>
windows平台下编辑的内容传到linux平台出现中文乱码的解决办法
查看>>
数据库实例: STOREBOOK > 用户
查看>>
发送键盘指令System.Windows.Forms.SendKeys.Send
查看>>