[USACO 2016 Dec Gold] Tutorial

本文解析了三道经典的算法题目,包括贪心算法求最小生成树、动态规划解决行走路径问题以及最短路径问题的不同解决方案。

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

Link:

传送门

A:

贪心从小到大插入,用并查集维护连通性

#include <bits/stdc++.h>

using namespace std;
#define X first
#define Y second
typedef double db;
typedef long long ll;
typedef pair<int,int> P;
const int MAXN=1e3+10;
int n,tot,cnt,f[MAXN];P dat[MAXN];
struct edge{int x,y;ll w;}e[MAXN*MAXN];

ll sqr(int x){return 1ll*x*x;}
bool cmp(edge x,edge y){return x.w<y.w;}
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&dat[i].X,&dat[i].Y),f[i]=i;
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++)
            e[++tot]={i,j,sqr(dat[i].X-dat[j].X)+sqr(dat[i].Y-dat[j].Y)};
    sort(e+1,e+tot+1,cmp);
    
    cnt=n;
    for(int i=1;i<=tot;i++)
    {
        int px=find(e[i].x),py=find(e[i].y);
        if(px!=py) f[px]=py,cnt--;
        if(cnt==1) return printf("%lld",e[i].w),0;
    }
    return 0;
}
Problem A

 

B:

$dp[1...n][1...m][0/1]$,其中0/1表示当前在哪一边

#include <bits/stdc++.h>

using namespace std;
#define X first
#define Y second
typedef double db;
typedef long long ll;
typedef pair<int,int> P;
const int MAXN=1e3+10,INF=0x3f3f3f3f;
ll dp[MAXN][MAXN][2];
int n,m;P dat[MAXN*2];

ll sqr(int x){return 1ll*x*x;}
ll dist(int a,int b){return sqr(dat[a].X-dat[b].X)+sqr(dat[a].Y-dat[b].Y);}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n+m;i++)
        scanf("%d%d",&dat[i].X,&dat[i].Y);
    
    memset(dp,0x3f,sizeof(dp));
    dp[1][0][0]=0;
    for(int i=0;i<=n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;k<2;k++)
            {
                if(i) dp[i+1][j][0]=min(dp[i+1][j][0],dp[i][j][0]+dist(i,i+1));
                if(j) dp[i+1][j][0]=min(dp[i+1][j][0],dp[i][j][1]+dist(n+j,i+1));
                if(i) dp[i][j+1][1]=min(dp[i][j+1][1],dp[i][j][0]+dist(i,n+j+1));
                if(j) dp[i][j+1][1]=min(dp[i][j+1][1],dp[i][j][1]+dist(n+j,n+j+1));
            }
    printf("%lld",dp[n][m][0]);
    return 0;
}
Problem B

 

C:

可以明显发现是最短路模型,但如果将一个点能不转弯走到的所有点的边都连上明显$TLE$

那么在跑最短路时多记录一维当前方向即可,每次转移判断是否要转向来决定是否增加代价

这样只要与不穿过其他点就能到达的点连边就行了

#include <bits/stdc++.h>

using namespace std;
#define X first
#define Y second
typedef double db;
typedef long long ll;
typedef pair<int,int> P;
const int MAXN=1e5+10,INF=0x3f3f3f3f;
int n,x,y,h1[MAXN],h2[MAXN],dist[MAXN][2],tot; 
struct edge{int nxt,to;}e1[MAXN<<2],e2[MAXN<<2];
struct node{int x,y,id;}tmp[MAXN],dat[MAXN];
struct Queue{int w,x,dir;};

bool cmp1(node a,node b){return a.x<b.x;}
bool cmp2(node a,node b){return a.y<b.y;}
bool operator < (Queue a,Queue b){return a.w>b.w;}
void add1(int x,int y)
{
    e1[++tot]={h1[x],y};h1[x]=tot;
    e1[++tot]={h1[y],x};h1[y]=tot;
}
void add2(int x,int y)
{
    e2[++tot]={h2[x],y};h2[x]=tot;
    e2[++tot]={h2[y],x};h2[y]=tot;
}
priority_queue<Queue> q;

int main()
{
    scanf("%d",&n);n+=2;
    scanf("%d%d",&x,&y);dat[1]=tmp[1]={x,y,1};
    scanf("%d%d",&x,&y);dat[n]=tmp[n]={x,y,n};
    for(int i=2;i<n;i++)
        scanf("%d%d",&dat[i].x,&dat[i].y),dat[i].id=i,tmp[i]=dat[i];
    
    sort(tmp+1,tmp+n+1,cmp1);
    for(int i=1;i<n;i++)
        if(tmp[i].x==tmp[i+1].x) 
            add1(tmp[i].id,tmp[i+1].id);
    sort(tmp+1,tmp+n+1,cmp2);
    for(int i=1;i<n;i++)
        if(tmp[i].y==tmp[i+1].y) 
            add2(tmp[i].id,tmp[i+1].id);
    
    memset(dist,0x3f,sizeof(dist));
    dist[1][0]=dist[1][1]=0;
    q.push(Queue{0,1,0});q.push(Queue{0,1,1});
    while(!q.empty())
    {
        Queue t=q.top();q.pop();
        if(dist[t.x][t.dir]<t.w) continue;
        
        for(int i=h1[t.x];i;i=e1[i].nxt)
            if(dist[e1[i].to][0]>dist[t.x][t.dir]+(t.dir!=0))
                dist[e1[i].to][0]=dist[t.x][t.dir]+(t.dir!=0),q.push(Queue{dist[e1[i].to][0],e1[i].to,0});
        for(int i=h2[t.x];i;i=e2[i].nxt)
            if(dist[e2[i].to][1]>dist[t.x][t.dir]+(t.dir!=1))
                dist[e2[i].to][1]=dist[t.x][t.dir]+(t.dir!=1),q.push(Queue{dist[e2[i].to][1],e2[i].to,1});
    }
    int res=min(dist[n][0],dist[n][1]);
    printf("%d",res==INF?-1:res);
    return 0;
}
Problem C

不过看了题解发现由于:

1、同一行/列可以直达任一点

2、每次代价增加必然是行列间转化

从而也可以仅考虑坐标,离散化后对于点$(x,y)$将$x$行和$y$列连边即可

 

转载于:https://www.cnblogs.com/newera/p/9615534.html

资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建与发布是提升开发效率和项目质量的关键环节。Jenkins Pipeline作为一种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实现Java项目的自动化构建与发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的一套工作流框架,它将原本分散在单个或多个节点上独立运行的任务串联起来,实现复杂流程的编排与可视化。它是Jenkins 2.X的核心特性之一,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称和描述,点击“确定”。 在Pipeline脚本中定义项目字典、发版脚本和预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于定义自动化构建和发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,定义了四个阶段:Checkout、Build、Push package和Deploy/Rollback。每个阶段都可以根据实际需求进行配置和调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率和项目质量。借助Pipeline,我们能够轻松实现自动化构建、测试和部署,从而提高项目的整体质量和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值