【NOIP2016提高A组集训第15场11.14】过河

18 篇文章 0 订阅

Description

这里写图片描述

Solution

一开始看到这道题的时候,就想,这不就是连边题吗!!!
然后,一通乱连,然后放弃治疗……
(i,j)表示第i个桩放第j个圆盘。
结果连边其实非常的简单:从0向(i,j)(如果能连的话)连权为c[j]的边,然后(i,j)向终点连权为0的边(如果能连的话)。
然后(i,j)向(p,q)连边(如果能连的话)
然后跑一次spfa就能拿60分了。
我们来优化一下连边。
我们可以发现如果(i,j)可以(p,q)连边的话,那么(i,j)也可以向(p,q+1…m)连边。
那么我们考虑一个(i,j)只想一个(p,k)连边且k是最小的那么p。所以(i,j)就需要向(i,j+1)连边。
找最小的p连边,按所有点到x的路径长度排序一下,随便搞搞就好了。O(n*n*m)
然后,就可以过了。

想跑的更快吗?

打dij或spfa优化。
spfa优化总结

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
const int maxn=257,mxx=257*257*257;
using namespace std;
typedef long long ll;
ll i,j,k,l,t,n,m,ans,cas,w,T,mm,o;
int first[maxn*maxn],last[maxn*maxn*150],next[maxn*maxn*150],num;
int data[mxx];
ll d[maxn*maxn],da,chang[maxn*maxn*150],r[maxn],c[maxn];
bool bz[maxn*maxn],az;
ll z,len;
struct node{ll r,c;}b[maxn];
struct nod{ll a,b;}a[maxn];
struct guhou{int a;double b;}e[maxn];
bool cmp(node x,node y){return x.r<y.r||x.r==y.r&&x.c<y.c;}
bool cmp1(guhou x,guhou y){return x.b<y.b;}
void add(int x,int y,ll z){
     last[++num]=y,next[num]=first[x],first[x]=num,chang[num]=z;
}
double ju(ll x,ll y,ll xx,ll yy){
    double z=sqrt((xx-x)*(xx-x)+(yy-y)*(yy-y));
    return z;
}
int hao(int x,int y){return n+(x-1)*m+y;}
void spfa(){
    int i,j,k,head=0,tail=1,now;
    double y;len=1;z=0;
    memset(d,127,sizeof(d));da=d[0];d[0]=0;ans=da;
    bz[0]=1;
    data[1]=0;
    while(head<tail){
        now=data[++head];
        if(len*d[now]>z){
            data[++tail]=now;
            continue;
        }
        z-=d[now];len--;
        if(d[now]>=ans){bz[now]=0;continue;}
        if(now==T&&ans>d[now]){
            ans=d[now];
        }
        rep(i,now){
            if(d[now]+chang[i]<=d[last[i]]){
                d[last[i]]=d[now]+chang[i];
                if(!bz[last[i]]){
                    bz[last[i]]=1;len++;
                    data[++tail]=last[i];z+=d[last[i]];
                    if(d[last[i]]<d[data[head+1]])swap(data[tail],data[head+1]);
                }
            }
        }
        bz[now]=0;
    }
}
int main(){
  //  freopen("river.in","r",stdin);
  //  freopen("river.out","w",stdout);
   // freopen("fan.in","r",stdin);
    for(scanf("%lld",&cas);cas;cas--){
        scanf("%lld%lld%lld",&n,&mm,&w);
        fo(i,1,n)scanf("%lld%lld",&a[i].a,&a[i].b);
        fo(i,1,mm)scanf("%lld%lld",&b[i].r,&b[i].c);
        memset(first,0,sizeof(first));num=m=0;
        sort(b+1,b+1+mm,cmp);b[mm+1].c=0x7fffffff;
        fo(i,1,mm){
            az=1;
            fo(j,i+1,mm){
                if(b[i].c>b[j].c){
                    az=0;
                    break;
                }
            }
            if(az)r[++m]=b[i].r,c[m]=b[i].c;
        }
        T=hao(n+1,1);
        fo(i,1,n){
            fo(j,1,m){
                if(r[j]>=a[i].b){
                    add(0,hao(i,j),c[j]);
                }
                if(r[j]+a[i].b>=w){
                    add(hao(i,j),T,0);
                }
            }
        }
        fo(i,1,n){
            fo(j,1,m-1){
                add(hao(i,j),hao(i,j+1),c[j+1]-c[j]);  
            }
        }
        fo(i,1,n){
            fo(k,1,n)e[k].a=k,e[k].b=ju(a[i].a,a[i].b,a[k].a,a[k].b);
            sort(e+1,e+1+n,cmp1);
            fo(j,1,m){
                o=1;
                fo(k,1,n){
                    if(e[k].a==i)continue;
                    while(o<=m&&(r[j]+r[o])*1.0<e[k].b)o++;
                    if(o==m+1)break;
                    add(hao(i,j),hao(e[k].a,o),c[o]);
                }
            }
        }
        spfa();
        if(d[T]==da)printf("impossible\n");
        else printf("%lld\n",d[T]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值