您的位置:首页 > 其它

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

2016-11-14 21:50 281 查看

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: