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;
}