題目連接:https://ac.nowcoder.com/acm/contest/882/F優化
題意:將2×n我的分紅兩組,每組n我的,求一個組中全部人和另一組的全部人的競爭值之和。spa
思路:code
比賽時看錯題了,覺得求得是每一隊人的競爭值之和,寫了兩個小時,提交時覺得會T,結果一直WA,自閉。。blog
看懂題後,就開始T了。。it
n<=14,用搜索+剪枝是能夠作的。搜索有C(2*n,n)的複雜度,但每種結果須要O(n*n)的複雜度來計算,總複雜度爲O(n*n*C(2*n,n)),確定會T。io
優化:簡化計算結果,先預處理每一行的和v2,v2[i]即第i我的和其它全部人的競爭值的和,用vector存儲已經選過的人,選擇下一我的x時,用v2[i]減去2×(全部的v1[x][i]),i是已經選過得人的編號,乘2是由於以前加入i時沒有減。這樣複雜度就降爲O(n*C(2*n,n)),由於題目給了4s,是能夠過的。class
另外,能夠把第1我的直接選上,由於第1我的確定要被其中1個隊選上,結果同樣,這樣能將複雜度減1倍。test
AC代碼:搜索
#include<cstdio> #include<algorithm> #include<vector> using namespace std; typedef long long LL; int n; LL v1[30][30],v2[30],ans; vector<int> vc; void dfs(int x,LL sum){ if(vc.size()==n){ if(sum>ans) ans=sum; return; } if(x>2*n) return; LL tmp=v2[x]; for(int i=0;i<vc.size();++i) tmp-=2*v1[x][vc[i]]; vc.push_back(x); dfs(x+1,sum+tmp); vc.pop_back(); dfs(x+1,sum); } int main(){ scanf("%d",&n); for(int i=1;i<=2*n;++i) for(int j=1;j<=2*n;++j) scanf("%lld",&v1[i][j]),v2[i]+=v1[i][j]; vc.push_back(1); dfs(2,v2[1]); printf("%lld\n",ans); return 0; }