[BOI2019][第K大问题][暴力剪枝]D2T1 Olympiads
目錄
- 題意
- 輸入格式
- 輸出格式
- 樣例
- Input
- Output
- 數(shù)據(jù)范圍
- 時間限制
- 思路
- 代碼
題意
有\(N\)個人,現(xiàn)在你要從中選出\(K\)個人出來,然后讓這\(K\)個人一起參加\(K\)場比賽。其中,每個人都要參加所有的比賽。
定義其中一場比賽的得分為這\(K\)個人的得分的最大值。然后定義這個隊(duì)的得分為\(K\)場比賽的得分的加和。
例如,\(K=3\)時,有一支3個人的隊(duì)伍,一共打3場比賽。第1個人在3場比賽中的得分分別為\((4, 5, 3)\),第2個人在3場比賽中的得分分別為 \((7, 3, 6)\), 第3個人在3場比賽中的得分分別為 \((3, 4, 5)\)。那么這個隊(duì)伍的總得分就是\(7+5+6=18\)。
現(xiàn)在你要求出的是,總分最第\(C\)大的隊(duì)伍的得分是多少。定義兩個隊(duì)伍不同,當(dāng)且僅當(dāng)存在兩個兩個隊(duì)伍的人的編號不同。
輸入格式
第一行3個整數(shù)分別表示\(N,K,C\);
接下來N行,每行K個整數(shù),表示每個人在每場比賽中的得分。
輸出格式
一行,輸出得分第\(C\)大的隊(duì)伍的得分。
樣例
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
數(shù)據(jù)范圍
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, 每個人的分?jǐn)?shù)大小不超過10.
4.(32 points) 1 ≤ N ≤ 500, 1 ≤ K ≤ 6, 1 ≤ C ≤ 2 000.
時間限制
\(2\ sec / 30\ sec\)
思路
首先聲明這是自己的方法,沒有看官方題解...
首先求一個得分最大的隊(duì)伍出來,怎么求呢?
就是讓每一場比賽的得分都盡量大,也就是取所有人中這場比賽得分最大的那個人。然后這樣子選完之后可能沒有選齊K個人,那么剩余的位置就隨便找人來補(bǔ)齊就好了。
然后仿照所有的求第k大的題目的做法,把這個隊(duì)伍塞到一個大根堆(priority_queue)中去,每次都從隊(duì)首取出一個當(dāng)前的最大答案,然后用這個隊(duì)伍進(jìn)行拓展,塞入其它沒有出現(xiàn)過的其他隊(duì)伍。
如何拓展呢?
最暴力的想法是,每次都將這個隊(duì)伍中的一個人換成另外一個人,然后在確定了這支新的隊(duì)伍沒有出現(xiàn)過之后,就將這支隊(duì)伍也塞到優(yōu)先隊(duì)列中去。
如何判斷之前是否重復(fù)呢?我用的是Hash,然后把Hash值塞到一個set里面去,就可以簡單的判重了。
考慮一下時間復(fù)雜度:一共要取出C次,就是\(O(C)\),每次都要枚舉將哪個人替換掉,也就是\(O(K)\)。還要枚舉替換成哪個人,也就是\(O(N)\)。替換了之后,還要算出新的隊(duì)伍的得分是多少,也就是\(O(K^2)\)的。然后還有set和priority_queue的時間復(fù)雜度,設(shè)為\(Const\)。那么總的時間復(fù)雜度就是\(O(N*K^3*C*Const)\),大概有\(216,000,000+\),好像跑不過...
考慮剪枝。考慮替換一個人的時候,只在N個人當(dāng)中選出那些替換之后會使得答案變小或不變的那些人進(jìn)行判重,判斷沒有出現(xiàn)過之后再選取其中的最大值進(jìn)行擴(kuò)展。這樣子總共擴(kuò)展出來的節(jié)點(diǎn)數(shù)就有原來的\(C*K*N\)變?yōu)榱?span id="ozvdkddzhkzd" class="math inline">\(C*K\),優(yōu)先隊(duì)列和set部分的時間就變小了。然后枚舉的時候,也被剪掉了不少。這樣子就可以跑到0.3s~0.4s左右。
代碼
實(shí)現(xiàn)的有點(diǎn)丑,但是算法還是很簡單暴力的。
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define MAXN 500 #define MAXK 6 #define MAXC 2000 #define MO 10000007 using 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<B.val;} priority_queue<state> 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<c;tmn++){fro=que.top();que.pop();Decode(fro.st,tmp1);for(int i=1;i<=k;i++)sp[tmp1[i]]=1;for(int i=1;i<=k;i++){LL mxst;int mxval=-1;for(int j=1;j<=n;j++)if(sp[j]==false){for(int p=1;p<=k;p++)tmp2[p]=tmp1[p];tmp2[i]=j;int val=GetVal(tmp2);if(val>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]<scr[i][j])mxpos=i;tmp[j]=mxpos;}sort(tmp+1,tmp+1+k);int len=unique(tmp+1,tmp+1+k)-tmp-1;for(int i=len+1;i<=k;i++)for(int j=1;j<=n;j++){bool Find=false;for(int p=1;p<i&&Find==false;p++)if(tmp[p]==j)Find=true;if(Find==false){tmp[i]=j;break;}}sort(tmp+1,tmp+1+k);LL ret=Encode(tmp);Insert(ret);que.push(state(GetVal(tmp),ret));int ans=Solve();printf("%d\n",ans);return 0; } /* 5 4 4 7 0 4 9 3 0 8 4 1 1 3 7 5 1 3 4 4 2 2 9*/轉(zhuǎn)載于:https://www.cnblogs.com/T-Y-P-E/p/11046377.html
總結(jié)
以上是生活随笔為你收集整理的[BOI2019][第K大问题][暴力剪枝]D2T1 Olympiads的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2019-06-12 学习日记 day3
- 下一篇: 初始化参数文件