kuangbin专题四 最短路练习从入门到熟练

Posted zhenghanghu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kuangbin专题四 最短路练习从入门到熟练相关的知识,希望对你有一定的参考价值。

【POJ 2253 Frogger】

这道题求从u到v中所有通路的最大边最小

我直接二分做了,但实际上这种题是最短路算法的变种,意义在于告诉我们spfa这些算法不仅能维护出最短路,稍加修改后可以维护出很多其他东西。

技术分享图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<string>
#include<stack>
#include<fstream>
#include<map>
#include<iomanip> 
#include<algorithm>
#include<vector>
#define INF 2e9
#define maxnode 200000
#define ll long long
#define lowbit(x) (x&(-x))
const int mod = 10007;
const int MAXN = 2e2 + 10;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
using namespace std;

struct node{
    int v,d;
    node(int v1,int d1): v(v1),d(d1) {}
};

vector<node> edges[MAXN];

int dist[MAXN],visit[MAXN],n;
void spfa(){
    for(int i=1;i<=n;i++) dist[i]=INF;
    dist[1]=0; visit[1]=1;
    queue<int> q;
    q.push(1);
    while( !q.empty() ){
        int u = q.front(); q.pop();
        visit[u]=0;
        for(int i=0;i<edges[u].size();i++){
            int v = edges[u][i].v;
            if( dist[v]>dist[u]+edges[u][i].d ){
                dist[v] = dist[u]+edges[u][i].d;
                if( !visit[v] ) q.push(v);
            }
        }
    }
    
}

int x[MAXN],y[MAXN];
double dis[MAXN][MAXN];

int main(){
    //ios::sync_with_stdio(false);
    int tc=0;
    while(1){
        scanf("%d",&n);
        if(n==0) break;
        for(int i=1;i<=n;i++) scanf("%d%d",x+i,y+i);
        
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                double x1 = abs(x[i]-x[j]);
                double y1 = abs(y[i]-y[j]);
                dis[i][j] = sqrt(x1*x1 + y1*y1);
                //cout<<i<<" "<<j<<" "<<dis[i][j]<<endl;
            }
        }
        
        double start=0,end=3000,mid;
        while( end-start>=0.00001 ){
            mid = (start+end)/2;
            for(int i=1;i<=n;i++) edges[i].clear();
            
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    if( mid>=dis[i][j] ) edges[i].push_back( node(j,1) );
                }
            }
            
            spfa();
            if( dist[2]!=INF ) end=mid;
            else start=mid;
        }
        printf("Scenario #%d
",++tc);
        printf("Frog Distance = %.3lf
",end);
        printf("
");
    }    
    
    return 0;
}
View Code

 

【POJ 1797 Heavy Transportation】

维护所有通路的最小边最大

那修改后的松弛操作就是 dist[v] = max( dist[v], min( dist[u], edges[u][i].d ) )

技术分享图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<string>
#include<stack>
#include<fstream>
#include<map>
#include<iomanip> 
#include<algorithm>
#include<vector>
#define INF 2e9
#define maxnode 200000
#define ll long long
#define lowbit(x) (x&(-x))
const int mod = 10007;
const int MAXN = 1e3 + 10;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
using namespace std;

struct node{
    int v,d;
    node(int v1,int d1): v(v1),d(d1) {}
};

vector<node> edges[MAXN];

int dist[MAXN],visit[MAXN],n,m;//dist[i]代表从源点到i点中所有通路的最小边最大值 
void spfa(){
    for(int i=1;i<=n;i++) dist[i]=0;
    dist[1]=INF; visit[1]=1;
    queue<int> q;
    q.push(1);
    while( !q.empty() ){
        int u = q.front(); q.pop();
        visit[u]=0;
        for(int i=0;i<edges[u].size();i++){
            int v = edges[u][i].v;
            int weight = min( edges[u][i].d,dist[u] );//weight是这条通路上的最小边 
            if( weight>dist[v] ){
                dist[v] = weight;
                if( !visit[v] ) {
                    //visit[v]=1;
                    q.push(v);
                }
            }
        }
    }
    
}

//找所有通路中最小边最大的 
int main(){
    //ios::sync_with_stdio(false);
    int t,tc=0; scanf("%d",&t); 
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            int u,v,d; scanf("%d%d%d",&u,&v,&d);
            edges[u].push_back( node(v,d) );
            edges[v].push_back( node(u,d) );
        }
        
        spfa();
        printf("Scenario #%d:
",++tc);
        printf("%d
",dist[n]);
        printf("
");
        
        for(int i=1;i<=n;i++) edges[i].clear();
    }    
    
    return 0;
}
View Code

 

【POJ 3268 Silver Cow Party】

想到跑flyod但n^3太慢就t了,实际上反向建边跑两边spfa就可以了!

技术分享图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<string>
#include<stack>
#include<fstream>
#include<map>
#include<iomanip> 
#include<algorithm>
#include<vector>
#define INF 2e9
#define maxnode 200000
#define ll long long
#define lowbit(x) (x&(-x))
const int mod = 10007;
const int MAXN = 1e3 + 10;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
using namespace std;

struct node{
    int v,d;
    node(int v1,int d1): v(v1),d(d1) {}
};
vector<node> edges[MAXN];
int vis[MAXN],dist1[MAXN],dist2[MAXN],n,m,x;

void spfa1(){
    for(int i=1;i<=n;i++) dist1[i]=INF;
    queue<int> q;
    q.push(x); vis[x]=1; dist1[x]=0;
    while(!q.empty()){
        int u = q.front(); q.pop();
        vis[u]=0;
        for(int i=0;i<edges[u].size();i++){
            int v = edges[u][i].v;
            int d = edges[u][i].d;
            if( dist1[u]+d<dist1[v] ){
                dist1[v]=dist1[u]+d;
                if( !vis[v] ){
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
    }    
}

void spfa2(){
    for(int i=1;i<=n;i++) dist2[i]=INF;
    queue<int> q;
    q.push(x); vis[x]=1; dist2[x]=0;
    while(!q.empty()){
        int u = q.front(); q.pop();
        vis[u]=0;
        for(int i=0;i<edges[u].size();i++){
            int v = edges[u][i].v;
            int d = edges[u][i].d;
            if( dist2[u]+d<dist2[v] ){
                dist2[v]=dist2[u]+d;
                if( !vis[v] ){
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
    }
    
}

int u[100005],v[100005],d[100005];


int main(){
    //ios::sync_with_stdio(false);
    while( scanf("%d%d%d",&n,&m,&x)!=EOF ){
        
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",u+i,v+i,d+i);
            edges[ u[i] ].push_back( node(v[i],d[i]) );
        }
        
        spfa1();
        for(int i=1;i<=n;i++) edges[i].clear();    
        for(int i=1;i<=m;i++) edges[ v[i] ].push_back( node(u[i],d[i]) );
        spfa2();
        
        int ans=-1;
        for(int i=1;i<=n;i++){//枚举所有cows
            ans = max( ans,dist1[i]+dist2[i] );
        }
        printf("%d
",ans);
        
        for(int i=1;i<=n;i++) edges[i].clear();            

    }    
    
    return 0;
}
View Code

 

【】

技术分享图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<string>
#include<stack>
#include<fstream>
#include<map>
#include<iomanip> 
#include<algorithm>
#include<vector>
#define INF 2e9
#define maxnode 200000
#define ll long long
#define lowbit(x) (x&(-x))
const int mod = 10007;
const int MAXN = 1e2 + 10;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
using namespace std;

struct exchange{
    int type;
    double r,c;
    exchange(int t1,double r1,double c1): type(t1),r(r1),c(c1) {}
};

vector<exchange> edges[MAXN];//edges[i]是拿着i货币能选择的一些兑换方案 

double d[MAXN],money;
int n,m,s;

struct node{
    int type;
    double m;//状态是拿着m个type钱
    node(int t1,double m1): type(t1),m(m1) {} 
};

bool bfs(){
    for(int i=1;i<=n;i++) d[i]=-INF;//最优性剪枝,d[i]为i种货币最多有多少个 
    queue<node> q;
    q.push( node(s,money) ); d[s]=money;
    while( !q.empty() ){
        node p = q.front(); q.pop();
        if( p.type==s && p.m>money ) return true;
        for(int i=0;i<edges[p.type].size();i++){//能怎么换 
            exchange e = edges[p.type][i];//在这个所换 
            double m1 = (p.m-e.c)*e.r;
            if( m1>d[ e.type ] ){
                d[e.type]=m1;
                q.push( node(e.type,m1) );
            }
        }
    }

    return false;
}

int main(){
    //ios::sync_with_stdio(false);
    while( scanf("%d%d%d%lf",&n,&m,&s,&money)!=EOF ){
        
        for(int i=1;i<=m;i++){
            int a,b; 
            double r1,c1,r2,c2; scanf("%d%d%lf%lf%lf%lf",&a,&b,&r1,&c1,&r2,&c2);
            edges[a].push_back( exchange(b,r1,c1) );
            edges[b].push_back( exchange(a,r2,c2) );
        }
        
        if( bfs() ) printf("YES
");
        else printf("NO
");
        
        for(int i=1;i<=n;i++) edges[i].clear();
    }    
    
    return 0;
}
View Code

 

以上是关于kuangbin专题四 最短路练习从入门到熟练的主要内容,如果未能解决你的问题,请参考以下文章

[kuangbin带你飞]专题四 最短路练习 I - Arbitrage(判断负环)

[kuangbin带你飞]专题四 最短路练习 POJ 2253 Frogger

[ An Ac a Day ^_^ ] [kuangbin带你飞]专题四 最短路练习 POJ 2387 Til the Cows Come Home

[kuangbin]带你飞之'最短路练习'专题(未完成)

算法系列学习Dijkstra单源最短路 [kuangbin带你飞]专题四 最短路练习 A - Til the Cows Come Home

[ An Ac a Day ^_^ ][kuangbin带你飞]专题四 最短路练习 POJ 2240 Arbitrage spfa求负环