Lightoj1002 【搜索】

题意:
两两之间的点的花费就是:从A点到B的一条路上某段的最大权值;给一个起点,求到各起点的最小花费。

思路:
一开始的思路:
n不是才500,我先建个图,然后DFS一下,不对,是2500;
如果直接暴搜,肯定T了。因为可能有一个环,然后你不能处理一个节点的向上节点。= =、T在这里,所以每次暴搜就相当于每次暴搜了整幅图;一开始写了一发,还以为再一次深刻理解DFS,然后T的我一脸懵逼,卧槽;不过还是加深了DFS的理解= =、。

①:如果要从DFS角度考虑,可以先求最小生成树,然后在树上DFS,主要是不存在环,比较方便;

②:另外一种就是最短路变形,spfa上直接搞搞就好了(这个还是要看对最短路的松弛熟练了没有);

思想还是 利用队列来操作,避免了重复的判断;


转化最小生成树的代码:

#include<stdio.h>
#include<queue>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int INF=0x3f3f3f3f;
const LL mod=1e9+7;
 
const int N=5e2+10;
struct edge{
    int x,y,w;
};
edge q[20000];
int num;
int pre[N];
 
bool cmp(edge x,edge y)
{
    return x.w<y.w;
}
 
struct asd{
    int to;
    int w;
    int next;
};
asd ma[20000];
int head[20000],tol;
int dis[N];
bool vis[N];
int n,m,t;
 
void add(int a,int b,int c)
{
    ma[tol].to=b;
    ma[tol].w=c;
    ma[tol].next=head[a];
    head[a]=tol++;
}
 
int Find(int x)
{
    int r=x;
    while(pre[r]!=r)
        r=pre[r];
    int i=x,j;
    while(pre[i]!=r)
    {
        j=pre[i];
        pre[i]=r;
        i=j;
    }
    return r;
}
 
void init()
{
    sort(q,q+num,cmp);
    for(int i=0;i<n;i++)
        pre[i]=i;
    tol=0;
    memset(head,-1,sizeof(head));
 
    for(int i=0;i<num;i++)
    {
        int fx=Find(q[i].x);
        int fy=Find(q[i].y);
        if(fx!=fy)
        {
            pre[fx]=fy;
            add(q[i].x,q[i].y,q[i].w);
            add(q[i].y,q[i].x,q[i].w);
        }
    }
}
 
void dfs(int u,int w)
{
    for(int v=head[u];v!=-1;v=ma[v].next)
    {
        int i=ma[v].to;
        if(vis[i])
            continue;
        dis[i]=max(w,ma[v].w);
        vis[i]=true;
        dfs(i,dis[i]);
    }
}
 
int main()
{
    int cas=1,T;
    int a,b,c;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        num=0;
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&c);
            q[num].x=a;
            q[num].y=b;
            q[num++].w=c;
        }
        scanf("%d",&t);
        init();
        memset(vis,false,sizeof(vis));
        memset(dis,-1,sizeof(dis));
        vis[t]=true;
        dfs(t,0);
        printf("Case %d:
",cas++);
        for(int i=0;i<n;i++)
        {
            if(i==t)
                puts("0");
            else if(dis[i]==-1)
                puts("Impossible");
            else
                printf("%d
",dis[i]);
        }
    }
    return 0;
}

最短路转化的代码:

#include<stdio.h>
#include<queue>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int INF=0x3f3f3f3f;
const LL mod=1e9+7;
 
const int N=5e2+10;
 
//struct asd{
//    int to;
//    int w;
//    int next;
//};
//asd q[N*N];
//int tol,head[N*N];
int ma[N][N];
int dis[N];
bool vis[N];
int n,m,t;
 
void spfa()
{
    queue<int>q;
    for(int i=0;i<n;i++)
    {
        vis[i]=false;
        dis[i]=INF;
    }
    vis[t]=1;
    dis[t]=0;
    q.push(t);
 
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=0;i<n;i++)
        {
            if(ma[u][i]==-1) continue;
            if(dis[i]>max(dis[u],ma[u][i]))
            {
                dis[i]=max(dis[u],ma[u][i]);
                if(!vis[i])
                {
                    vis[i]=1;
                    q.push(i);
                }
            }
        }
    }
}
 
int main()
{
    int cas=1,T;
    int a,b,c;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        memset(ma,-1,sizeof(ma));
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&c);
            if(ma[a][b]==-1)
                ma[a][b]=ma[b][a]=c;
            else
                ma[a][b]=ma[b][a]=min(c,ma[a][b]);
        }
        scanf("%d",&t);
        spfa();
        printf("Case %d:
",cas++);
        for(int i=0;i<n;i++)
        {
            if(dis[i]==INF)
                puts("Impossible");
            else
                printf("%d
",dis[i]);
        }
    }
    return 0;
}




原文地址:https://www.cnblogs.com/keyboarder-zsq/p/6216793.html