500:ICPCBalloons
题意:改变最少的气球颜色数目,使对应的题目的气球数目大于等于需求数目。
这里气球最多50种,值得注意的是题目种类最多15种,,赤裸裸的状态压缩!!!!
首先在不考虑气球大小的情况下,如果气球总数大于题目需求数,那么肯定是能解得;
然后我们从大到小把气球和题目一一对应,气球不够的直接补上(不管从哪补得),如果气球种类比题目种类少的话,在匹配剩下的多余的题目时,直接+上即可(因为肯定要从以前匹配过的气球里挪,即肯定是要涂色的)。
然后怎么转化为不考虑气球大小呢,我们先把M号放在一起,L号放在一起,在暴力枚举哪些题用L号,哪些题用M号即可;
over
int cmp(int a, int b) { return a>b; } // 在不考虑大小的情况下 int fun(vector<int> a, vector<int> b) //a为气球,b为题 { int len1 = a.size(); int len2 = b.size(); int sum1=0, sum2=0; for(int i = 0; i < len1; i++) sum1+=a[i]; for(int j = 0; j < len2; j++) sum2+=b[j]; if(sum1<sum2) //如果气球数目比题数目小,无解 return INF; int ans = 0; //否则肯定有可行解 for(int i = 0; i < len2; i++) { if(i<len1) //从大到小一一对应 { if(a[i]<b[i]) //如果当前颜色的气球不够过题数,肯定要从其他颜色气球拿,至于从哪拿不用考虑,肯定是有解的 ans+=b[i]-a[i]; } else { ans+=b[i]; //如果颜色种数少于题目种数,多余的题目种数肯定要用前面剩下的气球填满。 } } return ans; } int ICPCBalloons::minRepaintings(vector <int> balloonCount, string balloonSize, vector <int> maxAccepted) { int len1 = balloonCount.size(); int len2 = maxAccepted.size(); vector <int> M,L; for(int i = 0; i < len1; i++) { if(balloonSize[i]=='M') M.push_back(balloonCount[i]); else L.push_back(balloonCount[i]); } sort(M.begin(),M.end(),cmp); sort(L.begin(),L.end(),cmp); int ans = INF; for(int i = 0; i < (1<<len2); i++) { vector <int> Mq,Lq; for(int j = 0; j < len2; j++) { if((i>>j)&1)Mq.push_back(maxAccepted[j]); else Lq.push_back(maxAccepted[j]); } sort(Mq.begin(),Mq.end(),cmp); sort(Lq.begin(),Lq.end(),cmp); ans = min(ans,fun(M,Mq)+fun(L,Lq)); } if(ans==INF) return -1; else return ans; }
1000:
题意是说给你n个城市,n-1条路,有m个家庭,分别位于某些城市,它们想去其他城市度假,求所有家庭都走的路 的条数的期望。
我首先想到的是枚举家庭的 终点城市 集合,对每一种情况,暴力求解,复杂度是exp(49,50),爆了。
然而这个问题最重要的一点就是下面的转化:
我们只需要求 对于每一条边的 期望,然后依次加起来就是答案。
对于每一条边,设其端点分别是 a ,b。
设在这条边左边(a那边)的城市为ca,家庭为fa,同理cb,fb。
只有当左边的家庭fa都走到右边 且 右边的家庭fb都走到左边,才会都用到这条边。
其期望为pow(cb/(n-1), fa)*pow(ca/(n-1), fb);
怎么判断某个城市是在这条边左边还是右边呢?
如果在左边,则这个城市到a城市的距离应该小于到b城市的距离;反之则在右边。
然后我们会预先用flyod预处理任意两点间的最短路。
over
double FoxAndTouristFamilies::expectedLength(vector <int> A, vector <int> B, vector <int> f) { int n = A.size(); n++; int m = f.size(); int dis[60][60]; for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) dis[i][j] = 999999; for(int i = 0; i < n; i++) dis[i][i]=0; for(int i = 0; i < n-1; i++) { dis[A[i]][B[i]] = 1; dis[B[i]][A[i]] = 1; } for(int k = 0; k < n; k++) for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) { if(dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j] = dis[i][k]+dis[k][j]; } double ans = 0; for(int i = 0; i < n-1; i++) { int a = A[i], b = B[i]; int ca = 0, cb = 0; int fa = 0, fb = 0; for(int j = 0; j < n; j++) if(dis[j][a]<dis[j][b])ca++;else cb++; for(int j = 0; j < m; j++) if(dis[f[j]][a]<dis[f[j]][b])fa++;else fb++; ans += pow((double)cb/(double)(n-1), fa)*pow((double)ca/(double)(n-1), fb); } return ans; }