zoukankan      html  css  js  c++  java
  • [USACO 2016 Dec Gold] Tutorial

    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$列连边即可

  • 相关阅读:
    linux C/C++编程之库-动态库,静态库创建及使用
    类linux 系统iptables 系统初始化配置
    OS error set
    OpenWrt修改
    OpenWrt backfire trunk源码下载及编译
    OpenWrt compiles
    OpenWrt 学习网址
    nginx编译配置
    cocos2d-x中的坐标系
    SGU 231 Prime Sum 求&lt;=n内有多少对素数(a,b)使得a+b也为素数 规律题
  • 原文地址:https://www.cnblogs.com/newera/p/9615534.html
Copyright © 2011-2022 走看看