UVA 10457 ,uva10048 kruskal,最小瓶颈树,floyd

uva10457题意:m条路,每条路上必须维持速度v,现在有一辆车,启动能量和结束能量为a, b,途中消耗能量为经过路径最大速度减去最小速度,现在每次循环给定起点终点,问最小能量花费

这道题是个人赛的时候学长找的一道题,注意到q的值很小,所以对于每次询问都要进行计算,从小到大枚举边,作为最小值的边,然后再用比他大的边来跑kruskal,当起点和终点联通的时候(既处于同一个集合中),此条边减去最小值的边的值,便是ans。


  
  
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <vector> using namespace std;
const int maxn=200+10; const int maxm=1000+20; const int INF=2147483647; int G[maxn][maxn]; int n,m,q,be,ge,ANS; struct Edge{     int u,v,w;     bool operator <(const Edge &rhs)const {     return w<rhs.w;     } }; vector<Edge>edges; int p[maxn]; int find(int x){     return p[x]==x?x:p[x]=find(p[x]); } int solve(int s,int t){     int ans=INF;     for(int M=0;M<edges.size();M++){         for(int i=0;i<n;i++)p[i]=i;         for(int i=M;i<edges.size();i++){             int a=find(edges[i].u),b=find(edges[i].v);             if(a!=b)                 p[a]=b;             if(find(s)==find(t)){                 ans=min(ans,edges[i].w-edges[M].w);                 break;             }         }     }     return ans; } int main(){     while(scanf("%d%d",&n,&m)!=EOF){             edges.clear();         for(int i=0;i<m;i++){             int u,v,w;             cin>>u>>v>>w;             edges.push_back((Edge){u-1,v-1,w});         }         sort(edges.begin(),edges.end());         cin>>be>>ge;         cin>>q;         while(q--){             int s,t;             cin>>s>>t;             int an=be+ge+solve(s-1,t-1);             cout<<an<<endl;         }     } return 0; }

在网上查资料说这个题是最小瓶颈树,然而看了一下定义,所谓的最小瓶颈树就是最大的一条边最小。最大最小最容易想到的是二分,然而如果二分写bfs时间复杂度不够。可以用kruskal来求的最小生成树,最小生成树便是最小瓶颈树。此时两点路径上的最大值便是所求的答案。跑kruskal时候,当加入一条边,起点和终点联通的时候,这条边便是最大,也是答案。

uva10048

做完上一个题又想起前几天看到的uva10048,也是求两个点间的最大值最小的点,因为询问的数目比较多,紫书上给出的方法是写floyd,代码如下

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=100+10;
const int maxm=1000+100;
const int INF=2147483647;

int n,m,q,kase=0;
int G[maxn][maxn],d[maxn][maxn];

int main(){
    //freopen("in.txt","r",stdin);

    while(scanf("%d%d%d",&n,&m,&q)&&n&&m&&q){
            if(kase)cout<<""<<endl;


            kase++;
            for(int i=1;i<=n;i++)
                  for(int j=1;j<=n;j++)
                  G[i][j]=INF;


            for(int i=1;i<=m;i++){
                int a,b,c;
                cin>>a>>b>>c;
                G[a][b]=G[b][a]=c;
            }
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                d[i][j]=G[i][j];

            for(int k=1;k<=n;k++){
                 for(int i=1;i<=n;i++)
                   for(int j=1;j<=n;j++){
                     d[i][j]=min(d[i][j],max(d[i][k],d[k][j]));
                   }
            }
            cout<<"Case #"<<kase<<endl;

            for(int i=1;i<=q;i++){
                int a,b;
                cin>>a>>b;
                if(d[a][b]==INF)
                    cout<<"no path"<<endl;
                else
                     cout<<d[a][b]<<endl;

            }

    }
return 0;
}

虽然询问的数目多,但是依然可以承受跑kruskal,

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;

const int maxn=100+5;
const int maxm=1000+20;
struct Edge{
     int u,v,w;
     bool operator <(const Edge& rhs)const{
         return w<rhs.w;
     }
};
vector<Edge>edges;
int p[maxn];
int n,m,q,kase=0;
int find(int x){
    return p[x]==x?x:p[x]=find(p[x]);
}
int main(){
   // freopen("in.txt","r",stdin);

    while(scanf("%d%d%d",&n,&m,&q)==3&&n&&m&&q){
        kase++;
        if(kase!=1)
            cout<<""<<endl;
        cout<<"Case #"<<kase<<endl;
        edges.clear();
        for(int i=1;i<=m;i++){
            int u,v,w;
            cin>>u>>v>>w;
            edges.push_back((Edge){u,v,w});
        }
        sort(edges.begin(),edges.end());

        for(int i=1;i<=q;i++){
            bool jud=0;
            int a,b;
            cin>>a>>b;
            for(int i=1;i<=n;i++)p[i]=i;
            for(int j=0;j<edges.size();j++){
                int aa=find(edges[j].u),bb=find(edges[j].v);
                if(aa!=bb)
                    p[aa]=bb;
                if(find(a)==find(b)){
                    cout<<edges[j].w<<endl;
                    jud=1;
                    break;
                }
            }
         if(!jud)
            cout<<"no path"<<endl;
        }
    }
return 0;
}

当时一开始想写瓶颈树的时候,跑完最小生成树,想得到两个点间最长的边的时候,考虑了很多复杂的方法,用dfs得到路线然后再跑一边,代码又臭又长。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值