zoukankan      html  css  js  c++  java
  • 集合位置

    洛咕

    一句话题意:给定(n(n<=200))个点的坐标和m条边,求次短路.

    分析:这题我真的要喷死,刚开始写了个K(K=2)短路模板,愣是只有70分,看题解说每个点只能走一次,所以要判重,我就跟它一样判重,发现样例都过不去.白白刚了一个多小时.放一下这个辣鸡代码.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=1005;
    int n,m,a[N*N],b[N*N],x[N],y[N],visit[N];
    int tot,head[N],nxt[N*N],to[N*N];
    double c[N*N],w[N*N],dis[N];
    inline void add(int a,int b,double c){
    	nxt[++tot]=head[a];head[a]=tot;
    	to[tot]=b;w[tot]=c;
    }
    inline double calc(int i,int j){
    	return sqrt(1.0*(x[i]-x[j])*(x[i]-x[j])+1.0*(y[i]-y[j])*(y[i]-y[j]));
    }
    queue<int>q;
    inline void spfa(){
    	memset(dis,0x3f,sizeof(dis));
    	dis[n]=0;visit[n]=1;q.push(n);
    	while(q.size()){
    		int x=q.front();q.pop();
    		visit[x]=0;
    		for(int i=head[x];i;i=nxt[i]){
    			int y=to[i];
    			if(dis[y]>dis[x]+w[i]){
    				dis[y]=dis[x]+w[i];
    				if(!visit[y]){
    					q.push(y);
    					visit[y]=1;
    				}
    			}
    		}
    	}
    }
    struct ppx{
    	int id;double f,g;
    	bool operator <(const ppx &x)const{
    		return f+g>x.f+x.g;
    	}
    }temp,tmp;
    priority_queue<ppx>Q;
    inline void kth(){
        memset(visit,0,sizeof(visit));
        temp.id=1;temp.f=0;temp.g=0;Q.push(temp);
        while(Q.size()){
            temp=Q.top();Q.pop();
            int u=temp.id;++visit[u];
            if(visit[u]==2&&u==n){
                printf("%.2lf
    ",temp.f+temp.g);
                return;
            }
            else if(visit[u]>2)continue;
            for(int i=head[u];i;i=nxt[i]){
                tmp.id=to[i];
                tmp.f=temp.f+w[i];
                tmp.g=dis[to[i]];
                Q.push(tmp);
            }
        }
        puts("-1");
    }
    int main(){
    	n=read();m=read();
    	for(int i=1;i<=n;++i)x[i]=read(),y[i]=read();
    	for(int i=1;i<=m;++i){
    		a[i]=read();b[i]=read();
    		c[i]=calc(a[i],b[i]);
    		add(a[i],b[i],c[i]);
    		add(b[i],a[i],c[i]);
    	}
    	spfa();kth();
        return 0;
    }
    
    

    进入正题,我们先跑一遍完整的SPFA,预处理出最短路所经过的路径,用一个(pre[])记录前驱就好.然后每次删一条最短路径上的边再跑SPFA,得到的最小答案就是最短路了.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=505;
    int n,m;
    int x[N],y[N],visit[N],pre[N];
    int tot,head[N],nxt[N*N],to[N*N];
    double w[N*N],dis[N];
    inline double calc(int i,int j){
    	return sqrt(1.0*(x[i]-x[j])*(x[i]-x[j])+1.0*(y[i]-y[j])*(y[i]-y[j]));
    }
    inline void add(int a,int b,double c){
    	nxt[++tot]=head[a];head[a]=tot;
    	to[tot]=b;w[tot]=c;
    }
    inline void spfa(int x,int y){
    	for(int i=1;i<=n;++i)dis[i]=1e18;
    	memset(visit,0,sizeof(visit));
    	queue<int>q;dis[1]=0;visit[1]=1;q.push(1);
    	while(q.size()){
    		int u=q.front();q.pop();
    		visit[u]=0;
    		for(int i=head[u];i;i=nxt[i]){
    			int v=to[i];
    			if((u==x&&v==y)||(u==y&&v==x))continue;//如果这条边被删了,就不能走
    			if(dis[v]>dis[u]+w[i]){
    				dis[v]=dis[u]+w[i];
    				if(!x&&!y)pre[v]=u;//第一次SPFA,记录路径
    				if(!visit[v]){
    					visit[v]=1;
    					q.push(v);
    				}
    			}
    		}
    	}
    }
    int main(){
    	n=read();m=read();
    	for(int i=1;i<=n;++i)x[i]=read(),y[i]=read();
    	for(int i=1;i<=m;++i){
    		int a=read(),b=read();
    		double c=calc(a,b);//计算两点间距离
    		add(a,b,c);add(b,a,c);
    	}
    	spfa(0,0);double ans=1e18;
    	for(int i=n;pre[i];i=pre[i]){
    		spfa(pre[i],i);//每次删一条边
    		ans=min(ans,dis[n]);
    	}
    	if(ans==1e18)puts("-1");
    	else printf("%.2lf
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    Revit二次开发 C#程序员的佳好选择
    查询性能调优和索引优化那些事
    步步为营 .NET 设计模式学习笔记 十七、Flyweight(享元模式)
    初窥Ruby Metaprogramming
    线程间操作无效: 从不是创建控件“”的线程访问它
    全文搜索的,Lucene.net
    认识Lucene
    一些ObjectiveC学习资源
    步步为营 .NET 设计模式学习笔记 十五、Composite(组合模式)
    步步为营 .NET 设计模式学习笔记 十六、Facade(外观模式)
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11545465.html
Copyright © 2011-2022 走看看