SRM 561

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



你可能感兴趣的:(SRM 561)