代码改变世界

srm539 div1

2012-04-30 11:13  macaroniz  阅读(155)  评论(0)    收藏  举报

250pt

可以很容易想到,如果在确定用哪些box之后,我们可以直接算出该情况下x的范围 sum{low[i]} <= x <= sum{upper[i]}。

因此,只需要枚举一下所有选择box的方案,就可以求出这么一系列的x的范围。

但是由于这些范围可能存在区间重叠,因此我们需要按照(low,upper)排序后合并区间,因此我们只需要维护一个nowlow和nowUpper即可。

总的复杂度为O(15*2^15+2^15)

class Over9000Rocks
{
public:
    struct st
    {
        int low,upper;
    };
    vector<st> arr1,arr2;
    static bool cmp(const st &a,const st &b)
    {
        if(a.low != b.low) return a.low < b.low;
        else return a.upper < b.upper;
    }
    int countPossibilities(vector <int> lowerBound, vector <int> upperBound)
    {
        int ans = 0;
        int maxstate = 1 << lowerBound.size();
        arr1.clear();
        arr2.clear();
        for(int state = 0;state < maxstate;state++)
        {
            int low = 0,upper = 0;
            for(int i = 0;(1 << i) <= state;i++)
            {
                if(((1 << i) & state) != 0)
                {
                    low += lowerBound[i];
                    upper += upperBound[i];
                }
            }
            arr1.push_back((st){low,upper});
            //printf("%d %d\n",low,upper);
        }
        sort(arr1.begin(),arr1.end(),cmp);

        int lows= arr1[0].low;
        int uppers = arr1[0].upper;
        for(int i = 1;i < arr1.size();i++)
            if(arr1[i].low > uppers)
            {
                arr2.push_back((st){lows,uppers});
                lows = arr1[i].low;
                uppers = arr1[i].upper;
            }
            else if(arr1[i].upper > uppers)
                uppers= arr1[i].upper;
        arr2.push_back((st){lows,uppers});
        for(int i = 0;i < arr2.size();i++)
        {
            if(arr2[i].upper > 9000)
                ans += arr2[i].upper - (arr2[i].low > 9001 ? arr2[i].low : 9001) + 1;
        }
        return ans;
    }
};

 

550pt

首先这里有一个重要的结论,单源点最短路集合的并是一个有向无环图,也就是说,我们求出了0到其他所有点的最短路之后,定向一下,再将所有最短路合并之后构成一个新的图G,那么G是DAG图。

然后问题就很像是求图G的最小路径覆盖了,但是这里有一个问题,就是该题只需要覆盖1~N这N个顶点,但是图G中很可能存在N+1~K的顶点,因此为了转化到求最小路径覆盖的模型上,我们就需要将N+1~K这些顶点去掉,但是又不改变图G的联通性质。

这里还有一个重要的观察,如果i,j(i <=N,j<=N)之间在图G中有联通,且他们之间存在最短路p1->p2->...pm,且p1,p2....pm都是N+1~K中的顶点,那么我们可以直接在i,j之间连一条边。这样既去掉了N+1~K这些顶点,也不会改变G的连通性质,实际上,我们只需要在构图的时候,判断dist[0][i] == dist[0][j] + dist[i][j],即可确定i,j之间是否有边了。

至此,问题已经转化为了经典的求DAG图最小路径覆盖的问题。

const int oo = 10000000;
class SafeReturn
{
    public:
    int dist[55][55];
    int mat2[55][55];
    int vis[55];
    int belong[55];
    int N;
    bool find(int v)
    {
        for(int i = 0;i < N;i++)
            if(mat2[v][i] == 1 && vis[i] == 0)
            {
                //printf("%d %d\n",v,i);
                vis[i] = 1;
                if(belong[i] == -1 || find(belong[i]))
                {
                    belong[i] = v;
                    return true;
                }
            }
        return false;
    }

    int minRisk(int _N, vector <string> streets)
    {
    //$CARETPOSITION$
        memset(dist,0,sizeof(dist));
        N = _N;
        for(int i = 0;i < streets.size();i++)
            for(int j = 0;j < streets[i].length();j++)
            {
                if(streets[i][j] !='-')
                    dist[i][j] = streets[i][j] - '0';
                else dist[i][j] = oo;
            }
        for(int i = 0;i < streets.size();i++) dist[i][i] = 0;
        for(int k = 0;k < streets.size();k++)
            for(int i = 0;i < streets.size();i++)
                for(int j = 0;j < streets.size();j++)
                    if(dist[i][j] > dist[i][k] + dist[k][j])
                        dist[i][j] = dist[i][k] + dist[k][j];

        for(int i = 0;i <= N;i++)
        memset(mat2,0,sizeof(mat2));
        for(int i = 1;i <= N;i++)
            for(int j = 1;j <= N;j++)
                if(i != j && dist[0][i] == dist[0][j] + dist[i][j]) mat2[j-1][i-1] = 1;
        int ans = 0;
        memset(belong,0xff,sizeof(belong));

        for(int i = 0;i < N;i++)
        {
            memset(vis,0,sizeof(vis));
            if(find(i))
                ans++;
        }
        return N-ans;
    }
};

 

1000pt