USACO 2012 March Contest, Silver Division

这次比赛的成绩太悲剧了:

CHNChuanshun Yuan433
*xx*xx*xxx

**********


第一题 Tractor

题意:

给定一个二维坐标图,[1,1000]坐标大小,有n<=500000个障碍分布在格子上,然后给定一辆车的位置,问该车开到( 0, 0 ), 至少需要移除多少个障碍;


题解:

Solution Notes: This is a fairly standard shortest path problem, where we wish to find the shortest path from the initial location of the tractor to the outer boundary of the square with coordinates in the range 1..1000. Squares containing haybales cost 1 unit to cross, and all other squares cost 0 units. We could solve this problem using Dijkstra's algorithm, although the fact that costs are either zero or one allows us to use a slightly different (perhaps slightly simpler) approach using a pair of queues, one containing all the squares we intend to visit that are at distance zero away from our current location, and the other containing a list of all squares we intend to visit that are at distance one away from our current location. We always visit squares from the "zero away" quque, and when this empties out, we refill it with the contents of the "one away" queue. The total running time is therefore linear in the area of the square we are searching.


上面是官方题解,我的做法是优先队列+广搜,挂了,照着标程敲了编,贴下面了,居然说是Dijkstra算法,看来我对经典算法的理解都还没有到位!!!



#define mpair make_pair
#define pii pair<int,int>
#define MM(a,b) memset(a,b,sizeof(a));
typedef long long lld;
typedef unsigned long long u64;
#define maxn 1010

template<class T> bool up_max(T& a,const T& b){return b>a? a=b,1 : 0;}
template<class T> bool up_min(T& a,const T& b){return b<a? a=b,1 : 0;}

struct Point{
    int x,y;
    Point(int _x,int _y){x=_x,y=_y;}
    Point(){};
};

queue<Point> zero_away, one_away;
int a[maxn][maxn], d[maxn][maxn];

int relax(int curx,int cury,int x,int y){
    if(x>=0&&x<=1001&&y>=0&&y<=1001 && (d[x][y]==0 || d[curx][cury]+a[x][y] < d[x][y])){
        d[x][y]= d[curx][cury] + a[x][y];
        if( a[x][y]==0 ) zero_away.push( Point(x,y) );
        else one_away.push( Point(x,y) );
    }
}

int main()
{
    Point p;
    int i,n;
    while(scanf("%d%d%d", &n,&p.x,&p.y)!=EOF){
        d[ p.x ][ p.y ]= 1;
        zero_away.push( p );
        for(i=0;i<n;++i){
            scanf("%d%d", &p.x, &p.y);
            a[p.x][p.y]= 1;
        }

        while( !zero_away.empty() || !one_away.empty() ){
            if( zero_away.empty() )
                while( !one_away.empty() ){
                    zero_away.push( one_away.front() );
                    one_away.pop();
                }

            p= zero_away.front();
            zero_away.pop();
            relax( p.x, p.y, p.x-1, p.y );
            relax( p.x, p.y, p.x+1, p.y );
            relax( p.x, p.y, p.x, p.y-1 );
            relax( p.x, p.y, p.x, p.y+1 );
        }

        printf("%d\n", d[0][0]-1);
    }
}



第二题 Flowerpot

题意:

给定水平轴N个雨点,每个点距离地面高度为hi,则该雨点坐标为( xi, hi ), 雨同时落下,速度一样为单位时间,给定时间间隔D,问至少放一个多短的接水器,使其适当摆放后,第一滴雨与最后一滴雨滴落到该器皿的时间间隔>=D;  

D<= 1000,000;    坐标: 0-1000,000;  N<=10,000;


我是用二分答案+线段树做的;部分代码如下:

其中a[i], b[i]: 分别表示 x=i处竖直方向最低雨点的高度和最高雨点的高度;

后来发现题解里的方法更神奇,排序后,线性扫描,我太保守了!!!

void create(int u,int l,int r){
    if(l==r){
        T[u].minh= a[l], T[u].maxh= b[l];
        return;
    }
    int mid= (l+r)>>1;
    create(u+u,l,mid);
    create(u+u+1,mid+1,r);
    T[u].minh= min( T[u+u].minh, T[u+u+1].minh );
    T[u].maxh= max( T[u+u].maxh, T[u+u+1].maxh );
}

void get_val(int u,int l,int r,int tl,int tr, int& m1, int& m2){
    if(tl<=l&&r<=tr){
        m1= T[u].minh, m2= T[u].maxh;
        return;
    }
    int mid= (l+r)>>1;
    if(tr<=mid) get_val(u+u,l,mid,tl,tr,m1,m2);
    else if(tl>mid) get_val(u+u+1,mid+1,r,tl,tr,m1,m2);
    else{
        int t1,t2,t3,t4;
        get_val(u+u,l,mid,tl,mid,t1,t2);
        get_val(u+u+1,mid+1,r,mid+1,tr,t3,t4);
        m1= min( t1, t3 );
        m2= max( t2, t4 );
        return;
    }
}

bool judge(int mid){
    int l= Left, r= Right-mid;
    for(int i=l;i<=r;++i){
        int m1= -1, m2= -1;
        get_val( 1, Left, Right, i, i+mid, m1, m2 );
        if( m2-m1 >= D ) return 1;
    }
    return 0;
}


题解:

Solution Notes: We first sort all the points on x, then sweep a pair of vertical "sweep lines" from left to right through the scene. The y values of points between the sweep lines are stored in a data structure that can quickly find the min and max, such as an STL multiset (which we have used below) or a pair of priority queues. Whenever the difference between the max and min y coordinates is at least D, we check if this represents the best flowerpot width so far, and then advance the left sweep line; otherwise, we advance the right sweep line. The total running time is O(N log N).

标程:

#define mpair make_pair
#define pii pair<int,int>
#define MM(a,b) memset(a,b,sizeof(a));
typedef long long lld;
typedef unsigned long long u64;
#define maxn
#define inf 200000000

template<class T> bool up_max(T& a,const T& b){return b>a? a=b,1 : 0;}
template<class T> bool up_min(T& a,const T& b){return b<a? a=b,1 : 0;}

int n,d;
multiset<int>window;

int get_min(){return *window.begin();}
int get_max(){return *window.rbegin();}

int main()
{
    freopen("1.in","r",stdin);
    int i,j,x,y,ans= inf;
    vector< pii > P;

    scanf("%d%d", &n,&d);
    for(i=0;i<n;++i){
        scanf("%d%d", &x,&y);
        P.push_back( mpair( x, y ) );
    }

    sort( P.begin(), P.end() );
    // sweep_line;
    i=j=0;
    window.insert( P[0].second );
    while(1){
        if( get_max() - get_min() >= d ){
            up_min( ans, P[j].first-P[i].first );

            multiset<int>::iterator it= window.find( P[i++].second );
            window.erase( it );
        }
        else{
            if(j==n-1) break;
            window.insert( P[++j].second );
        }
    }

    printf("%d\n", ans==inf ? -1 : ans );
}



第三题 Landscaping     我不会这题

题意:

给定一个序列,要求用最小的代价转换成另一个序列,见下面的英文吧!

题解:

转换成Edit distance来做,表示从来不知道有这东西;

Problem:

Farmer John is building a nicely-landscaped garden, and needs to move alarge amount of dirt in the process.The garden consists of a sequence of N flowerbeds (1 <= N <= 100), whereflowerbed i initially contains A_i units of dirt. Farmer John would liketo re-landscape the garden so that each flowerbed i instead contains B_iunits of dirt. The A_i's and B_i's are all integers in the range 0..10.To landscape the garden, Farmer John has several options: he can purchaseone unit of dirt and place it in a flowerbed of his choice for $X. He canremove one unit of dirt from a flowerbed of his choice and have it shippedaway for $Y. He can also transport one unit of dirt from flowerbed i toflowerbed j at a cost of $Z times |i-j|. Please compute the minimum totalcost for Farmer John to complete his landscaping project.


http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Dynamic/Edit/   这个资料关于Edit distance;

Analyse:

Solution Notes: We transform each landscape pattern into an array of length at most 1000 by listing out the locations of the individual units of dirt in the landscape in order. For example, if we have a landscape with heights 3,1,4,1, we would transform this into the sequence 0,0,0,1,2,2,2,2,3 (e.g., there are 4 units of dirt at position 2). Our problem now reduces to something very close to the computation of the "edit distance" between two sequences, which is a classical dynamic programming problem. Our goal is to transform one landscape sequence into another at minimum cost given three possible operations: insertion of a new character (at cost X), deletion of a character (at cost Y), or modification of a character (at cost Z times the magnitude of the change). This can be accomplished in O(N^2) time (where N=1000) using dynamic programming, as shown below. Each subproblem C[i][j] we solve along the way represents the minimum cost of transforming just the first i characters of the source sequence into just the first j characters of the target sequence.


标程:

#define mpair make_pair
#define pii pair<int,int>
#define MM(a,b) memset(a,b,sizeof(a));
typedef long long lld;
typedef unsigned long long u64;
#define maxn 1010
#define inf 2000000000

template<class T> bool up_max(T& a,const T& b){return b>a? a=b,1 : 0;}
template<class T> bool up_min(T& a,const T& b){return b<a? a=b,1 : 0;}

int Abs(int x){return x>0?x:-x;}

int na,nb,X,Y,Z;
int a[maxn], b[maxn], c[maxn][maxn];

int main()
{
    int i,j,n;
    cin>>n>>X>>Y>>Z;
    na=0, nb=0;

    for(i=0;i<n;++i){
        scanf("%d", &j);
        while(j>0){
            a[++na]= i; --j;
        }
        scanf("%d", &j);
        while(j>0){
            b[++nb]= i; --j;
        }
    }

    for(j=0;j<=nb;++j) c[0][j]= j*X;  // i<=nb;
    for(i=0;i<=na;++i) c[i][0]= i*Y;  // i<=na;

    for(i=1;i<=na;++i){
        for(j=1;j<=nb;++j){
            c[i][j]= inf;
            up_min( c[i][j], c[i][j-1]+ X );
            up_min( c[i][j], c[i-1][j]+ Y );
            up_min( c[i][j], c[i-1][j-1] + Z * Abs(a[i]-b[j]) );
        }
    }

    printf("%d\n", c[na][nb]);
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值