[kuangbin带你飞] - C - Heavy Transportation (最大生成数/DJS/二分)

Heavy Transportation

题目链接:专题四 最短路练习 - C - Heavy Transportation POJ - 1797

题意

给你n个点,m条边,并且每条边都有一个权值,定义Min1为一条路径中的最小边权值,求从点1开始到达点N最大的Min1


思路一 (二分+Djs)

既然是最大的最小边,那么用二分应该是没问题的,我看了一下数据,点小于等于1e3,数据量不大,我就简单二分套了个迪杰斯特拉


代码一

/*
Time : 1172
Mem  : 4.7
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <ctime>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b)   memset(a,b,sizeof(a))
#define sz(x) ((int)(x).size())
#define pb push_back

typedef long long ll;
const int INF = (int)0x3f3f3f3f;
const int MAXN = (int)1e3+7;

int N,M;
int S,E;

int G[MAXN][MAXN];
int dis[MAXN];
int vis[MAXN];

bool OK(int n){
    mmm(dis,0x3f);
    mmm(vis,0);
    dis[S] = 0;

    int mn,now;
    rep(i,1,N){
        mn = INF,now = 0;
        rep(j,1,N){
            if (!vis[j] && dis[j] < mn){
                mn = dis[j];
                now = j;
            }
        }
        if (now == 0)break;
        vis[now] = 1;

        rep(j,1,N){
            if (G[now][j] >= n && dis[j] > G[now][j]+dis[now]){
                dis[j] = G[now][j]+dis[now];
            }
        }

    }
    if (dis[E] != INF) return 1;
    else               return 0;
}

void initAll(){
    mmm(G,0x3f);
    mmm(dis,0x3f);
    mmm(vis,0);
}

int main()
{
    int T;
    scanf("%d",&T);
    rep(ca,1,T) {
        initAll();
        scanf("%d %d",&N,&M);
        rep(i,1,M){
            int x,y,c;
            scanf("%d %d %d",&x,&y,&c);
            G[x][y] = G[y][x] = c;
        }
        S = 1,E = N;

        int l = 0,r = 1e6+2;
        while (l <= r){
            int m = (l+r)>>1;
            if (OK(m)) l = m+1;
            else       r = m-1;
        }
        printf("Scenario #%d:\n%d\n\n",ca,r);
    }
}

/*
2
3 3
1 2 3
1 3 5
2 3 5
3 3
1 2 30
1 3 40
2 3 50
*/

思路二 (直接 Djs)

看了大神的时间,我发现我的时间消耗基本上是最多的了,原来别人没有使用二分,而是直接用了一个迪杰斯特拉,dis里面储存的不是最短路了,而是到这个点所需要的Min1。这样别人就只需要用一次迪杰斯特拉了。


代码二 (邻接表)

/*
Time : 391
Mem  : 4.7
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <ctime>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b)   memset(a,b,sizeof(a))
#define sz(x) ((int)(x).size())
#define pb push_back

typedef long long ll;
const int INF = (int)0x3f3f3f3f;
const int MAXN = (int)1e3+7;

int N,M;
int S,E;

int G[MAXN][MAXN];
int dis[MAXN];
int vis[MAXN];

int Djs(){

    int mn,now;
    rep(i,1,N){
        dis[i] = G[1][i];
    }//好吧预处理还是很重要的

    rep(i,1,N){
        mn = 0,now = 0;
        rep(j,1,N){
            if (!vis[j] && dis[j] > mn){
                mn = dis[j];
                now = j;
            }
        }
        if (now == 0)break;
        vis[now] = 1;

        //从当前dis最大的点开始向周围松弛
        rep(j,1,N){
            if (dis[j] < min(G[now][j],dis[now])){ // 如果这个点的dis比G[now][j]和dis[now]的最小值还小就替换
                dis[j] = min(G[now][j],dis[now]);
            }
        }
    }
    return dis[E];
}

void initAll(){
    mmm(G,0);
    mmm(vis,0);
}

int main()
{
    int T;
    scanf("%d",&T);
    rep(ca,1,T) {
        initAll();
        scanf("%d %d",&N,&M);
        rep(i,1,M){
            int x,y,c;
            scanf("%d %d %d",&x,&y,&c);
            G[x][y] = G[y][x] = c;
        }
        S = 1,E = N;

        printf("Scenario #%d:\n%d\n\n",ca,Djs());
    }
}

/*
2
3 3
1 2 3
1 3 5
2 3 5
3 3
1 2 30
1 3 40
2 3 50
*/

代码三 (vector核心代码)

/*
Time : 329
Mem  : 1.8
*/
struct Node{
    int to,cost;
    Node(int t=0,int c=0):to(t),cost(c){}
};
vector<Node> vp[MAXN];
queue<int> qu;

int Djs(){
    while (!qu.empty())qu.pop();
    qu.push(S);

    while (!qu.empty()){
        int k = qu.front();
        qu.pop();

        rep(i,0,sz(vp[k])-1){
            int t = vp[k][i].to;
            int c = vp[k][i].cost;
            if (k == 1) dis[t] = c,qu.push(t);  //这步很关键
            else if (dis[t] < min(dis[k],c)){
                dis[t] = min(dis[k],c);
                qu.push(t);
            }
        }
    }
    return dis[E];
}

思路三 (最大生成树)

其实就是求最大生成树的最小边权,但是这里其实还有个小陷阱,就是所有的点不需要全部都连接,只要1和连接起来即可。


代码四 (Kruskal)

/*
Time : 282
Mem  : 12.6
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <ctime>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b)   memset(a,b,sizeof(a))
#define sz(x) ((int)(x).size())
#define pb push_back

typedef long long ll;
const int INF  = (int)0x3f3f3f3f;
const int MAXN = (int)1e3+7;
int N,M;

struct Node{
    int x,y,c;
    Node(int x = 0,int y = 0,int c = 0):x(x),y(y),c(c){}
}G[MAXN*MAXN];

bool cmp(const Node& a,const Node& b){
    return a.c > b.c;
}

int fa[MAXN];

int find1(int x){
    if (x != fa[x])fa[x] = find1(fa[x]);
    return fa[x];
}

bool Same(int x,int y){
    return find1(x) == find1(y);
}

void Union(int x,int y){
    int u = find1(x),v = find1(y);
    if (u == v)return ;
    fa[u] = v;
}

int Kruskal(){
    int res = INF;
    sort(G+1,G+1+M,cmp);
    rep(i,1,M){
        if (!Same(G[i].x,G[i].y)){
            Union(G[i].x,G[i].y);
            res = min(res,G[i].c);
        }
        if (Same(1,N))break;
    }
    return res;
}

void init(){
    rep(i,0,N)fa[i] = i;
}

int main()
{
    int T;
    scanf("%d",&T);
    rep(ca,1,T){
        scanf("%d %d",&N,&M);
        init();
        rep(i,1,M){
            scanf("%d %d %d",&G[i].x,&G[i].y,&G[i].c);
        }
        printf("Scenario #%d:\n%d\n\n",ca,Kruskal());
    }
}

代码五 (Prim)

/*
Time : 360
Mem  : 4.7
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <ctime>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b)   memset(a,b,sizeof(a))
#define sz(x) ((int)(x).size())
#define pb push_back

typedef long long ll;
const int INF  = (int)0x3f3f3f3f;
const int MAXN = (int)1e3+7;
int G[MAXN][MAXN];
int low[MAXN];
int vis[MAXN];
int N,M;

int Prim(){
    int res = INF;
    rep(i,1,N){
        low[i] = G[1][i];
    }
    vis[1] = 1;
    rep(i,1,N){
        int mn = -INF,id = 0;
        rep(j,1,N){
            if (!vis[j] && mn < low[j]){
                mn = low[j];
                id = j;
            }
        }        
        res = min(res,mn);
        vis[id] = 1;
        if (id == N)break;
        rep(j,1,N){
            if (!vis[j] && low[j] < G[id][j]){
                low[j] = G[id][j];
            }
        }
    }
    return res;
}

void init(){
    mmm(G,-1);
    mmm(vis,0);
    mmm(low,-1);
}

int main()
{
    int T;
    scanf("%d",&T);
    rep(ca,1,T){
        scanf("%d %d",&N,&M);
        init();
        int x,y,w;
        rep(i,1,M){
            scanf("%d %d %d",&x,&y,&w);
            G[x][y] = G[y][x] = w;
        }
        printf("Scenario #%d:\n%d\n\n",ca,Prim());
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41428565/article/details/80165979
今日推荐