USACO 2016 December Contest总结

本文提供了三道算法竞赛题目的解题思路及代码实现,包括最小通信距离问题的二分查找解决方法,点集访问序列的动态规划算法,以及激光与镜面反射问题的离散化与BFS算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

比赛链接

T1 Moocast

题目链接

题目大意:确定一个最小的通信距离使得一个平面上给定一些点直接或间接联通。

思路:二分。五分钟做出来了。。。

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<cctype>
#define pa pair<int,int>
#define INF 0x3f3f3f3f
#define inf 0x3f
#define fi first
#define se second
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pb push_back

using namespace std;

inline ll read()
{
    long long f=1,sum=0;
    char c=getchar();
    while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}
    while (isdigit(c)) {sum=sum*10+c-'0';c=getchar();}
    return sum*f;
}
const int MAXN=1010;
struct node
{
    int x,y;
};
node a[MAXN];
int fa[MAXN],n;
int find(int x)
{
    if (fa[x]!=x) fa[x]=find(fa[x]);
    return fa[x];
}
bool check(int mid)
{
    for (int i=1;i<=n;i++)
        fa[i]=i;
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=n;j++)
        {
            ll dis=(a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y);
            if (dis<=(ll)mid)
            {
                int f1=find(i),f2=find(j);
                if (f1!=f2) fa[f1]=f2;
            }
        }
    }
    int anc=find(1);
    for (int i=2;i<=n;i++)
        if (find(i)!=anc)
            return 0;
    return 1;
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d%d",&a[i].x,&a[i].y);
    int l=0,r=1e9,mid,ans;
    while (l<=r)
    {
        mid=(l+r)>>1;
        if (check(mid))
            ans=mid,r=mid-1;
        else
            l=mid+1;
    }
    cout<<ans;
    return 0;
}

T2 Cow Checklist

题目链接

题目大意:平面上有两组点,分别是N个,M个。
你要从第一组的第一个开始访问所有点,再回到第一组的最后一个。要求同一组内编号小的点必须在编号大的点之前访问。定义耗损为两个点之间的距离的平方。构造一个访问序列使得耗损最小,求最小耗损。

思路:DP
- f[i][j][0/1] f [ i ] [ j ] [ 0 / 1 ] 表示第一个序列的前i个点,第二个序列的前j个点被访问过,你现在在第一组点还是在第二组点。
- 转移:

f[i][j][0]=min(f[i1][j][1]+dis,f[i1][j][0]+dis)f[i][j][1]=min(f[i][j1][0]+dis,f[i][j1][1]+dis) { f [ i ] [ j ] [ 0 ] = m i n ( f [ i − 1 ] [ j ] [ 1 ] + d i s , f [ i − 1 ] [ j ] [ 0 ] + d i s ′ ) f [ i ] [ j ] [ 1 ] = m i n ( f [ i ] [ j − 1 ] [ 0 ] + d i s , f [ i ] [ j − 1 ] [ 1 ] + d i s ′ )

- 其中dis为两点之间距离。

代码忘记上传了。。。

T3 Lasers and Mirrors

题目链接

题目大意:二维平面内有 N(N106) N ( N ≤ 10 6 ) 个点,有一个激光发射器和一个接收器。现在要在点上安装镜子(光线只能垂直于坐标轴),问最少安装几个镜子才能让接收器收到激光 ,或不可能。

思路:先离散化,然后BFS。
- 考察了对iterator的使用。。。

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<cctype>
#define pa pair<int,int>
#define INF 0x3f3f3f3f
#define inf 0x3f
#define fi first
#define se second
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pb push_back

using namespace std;

inline ll read()
{
    long long f=1,sum=0;
    char c=getchar();
    while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}
    while (isdigit(c)) {sum=sum*10+c-'0';c=getchar();}
    return sum*f;
}
const int MAXN=100010;
struct node
{
    int x,y;
};
node a[MAXN];
vector <int> vx,vy;
const int dx[4]={0,1,0,-1};
const int dy[4]={1,0,-1,0};
vector <int> x[MAXN],y[MAXN];
bool visit[MAXN][5];
queue <pair<pa,pa> > q;
map <pa,int> id; 
#define ps(x,y,a,b) q.push(make_pair(make_pair(x,y),make_pair(a,b)))
int main()
{
    int n;
    node st,ed;
    scanf("%d%d%d%d%d",&n,&st.x,&st.y,&ed.x,&ed.y);
    vx.push_back(st.x),vy.push_back(st.y);
    vx.push_back(ed.x),vy.push_back(ed.y);
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d",&a[i].x,&a[i].y);
        vx.push_back(a[i].x),vy.push_back(a[i].y);
    }
    sort(vx.begin(),vx.end()),sort(vy.begin(),vy.end());
    vx.resize(unique(vx.begin(),vx.end())-vx.begin());
    vy.resize(unique(vy.begin(),vy.end())-vy.begin());
    for (int i=1;i<=n;i++)
    {
        a[i].x=lower_bound(vx.begin(),vx.end(),a[i].x)-vx.begin()+1;
        a[i].y=lower_bound(vy.begin(),vy.end(),a[i].y)-vy.begin()+1;
        id[make_pair(a[i].x,a[i].y)]=i;
        x[a[i].x].push_back(a[i].y);
        y[a[i].y].push_back(a[i].x);
    }
    st.x=lower_bound(vx.begin(),vx.end(),st.x)-vx.begin()+1;
    st.y=lower_bound(vy.begin(),vy.end(),st.y)-vy.begin()+1;
    ed.x=lower_bound(vx.begin(),vx.end(),ed.x)-vx.begin()+1;
    ed.y=lower_bound(vy.begin(),vy.end(),ed.y)-vy.begin()+1;
    x[st.x].push_back(st.y);
    y[st.y].push_back(st.x);
    x[ed.x].push_back(ed.y);
    y[ed.y].push_back(ed.x);
    for (int i=1;i<MAXN;i++)
        sort(x[i].begin(),x[i].end()),sort(y[i].begin(),y[i].end());
    int posx,posy;
    vector <int>::iterator it;
    it=upper_bound(x[st.x].begin(),x[st.x].end(),st.y);
    if (it!=x[st.x].end())
    {
        posx=st.x,posy=*it;
        ps(posx,posy,1,0);
    }
    it=lower_bound(x[st.x].begin(),x[st.x].end(),st.y);
    if (it!=x[st.x].begin())
    {
        it--;
        posx=st.x,posy=*it;
        ps(posx,posy,3,0);
    }
    it=upper_bound(y[st.y].begin(),y[st.y].end(),st.x);
    if (it!=y[st.y].end())
    {
        posx=*it,posy=st.y;
        ps(posx,posy,2,0);
    }
    it=lower_bound(y[st.y].begin(),y[st.y].end(),st.x);
    if (it!=y[st.y].begin())
    {
        it--;
        posx=*it,posy=st.y;
        ps(posx,posy,4,0);
    }
    while (!q.empty())
    {
        pair <pa,pa> now=q.front();
        q.pop();
        if (now.fi.fi==ed.x && now.fi.se==ed.y)
        {
            cout<<now.se.se;
            return 0;
        }
        int step=now.se.se;
        visit[id[make_pair(now.fi.fi,now.fi.se)]][now.se.fi]=1;
        int nx=now.fi.fi,ny=now.fi.se;
        if (now.se.fi==1)
        {
            it=upper_bound(x[nx].begin(),x[nx].end(),ny);
            if (it!=x[nx].end())
            {
                posx=nx,posy=*it;
                if (!visit[id[make_pair(posx,posy)]][1])
                    ps(posx,posy,1,step);
            }
            it=upper_bound(y[ny].begin(),y[ny].end(),nx);
            if (it!=y[ny].end())
            {
                posx=*it,posy=ny;
                if (!visit[id[make_pair(posx,posy)]][2])
                    ps(posx,posy,2,step+1);
            }
            it=lower_bound(y[ny].begin(),y[ny].end(),nx);
            if (it!=y[ny].begin())
            {
                it--;
                posx=*it,posy=ny;
                if (!visit[id[make_pair(posx,posy)]][4])
                    ps(posx,posy,4,step+1);
            }
        }
        else if (now.se.fi==2)
        {
            it=upper_bound(y[ny].begin(),y[ny].end(),nx);
            if (it!=y[ny].end())
            {
                posx=*it,posy=ny;
                if (!visit[id[make_pair(posx,posy)]][2])
                    ps(posx,posy,2,step);
            }
            it=upper_bound(x[nx].begin(),x[nx].end(),ny);
            if (it!=x[nx].end())
            {
                posx=nx,posy=*it;
                if (!visit[id[make_pair(posx,posy)]][1])
                    ps(posx,posy,1,step+1);
            }
            it=lower_bound(x[nx].begin(),x[nx].end(),ny);
            if (it!=x[nx].begin())
            {
                it--;
                posx=nx,posy=*it;
                if (!visit[id[make_pair(posx,posy)]][1])
                    ps(posx,posy,3,step+1);
            }
        }
        else if (now.se.fi==3)
        {
            it=lower_bound(x[nx].begin(),x[nx].end(),ny);
            if (it!=x[nx].begin())
            {
                it--;
                posx=nx,posy=*it;
                if (!visit[id[make_pair(posx,posy)]][1])
                    ps(posx,posy,3,step);
            }
            it=upper_bound(y[ny].begin(),y[ny].end(),nx);
            if (it!=y[ny].end())
            {
                posx=*it,posy=ny;
                if (!visit[id[make_pair(posx,posy)]][2])
                    ps(posx,posy,2,step+1);
            }
            it=lower_bound(y[ny].begin(),y[ny].end(),nx);
            if (it!=y[ny].begin())
            {
                it--;
                posx=*it,posy=ny;
                if (!visit[id[make_pair(posx,posy)]][4])
                    ps(posx,posy,4,step+1);
            }               
        }
        else
        {
            it=lower_bound(y[ny].begin(),y[ny].end(),nx);
            if (it!=y[ny].begin())
            {
                it--;
                posx=*it,posy=ny;
                if (!visit[id[make_pair(posx,posy)]][4])
                    ps(posx,posy,4,step);
            }
            it=upper_bound(x[nx].begin(),x[nx].end(),ny);
            if (it!=x[nx].end())
            {
                posx=nx,posy=*it;
                if (!visit[id[make_pair(posx,posy)]][1])
                    ps(posx,posy,1,step+1);
            }
            it=lower_bound(x[nx].begin(),x[nx].end(),ny);
            if (it!=x[nx].begin())
            {
                it--;
                posx=nx,posy=*it;
                if (!visit[id[make_pair(posx,posy)]][1])
                    ps(posx,posy,3,step+1);
            }
        }
    }
    cout<<-1<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值