最短路径

适合入门

POJ   2139

改错到怀疑人生再见结果发现存数组的时候把 j  写成了 i 。

另外还容易错的点是 牛的标记是从1开始的,要不存数组的时候就变成从1开始,要不就在输入牛标记存入时就要减去1


用到了Floyd-Warshall算法

多源最短路问题

#include <iostream>

#include <vector>

#include <map>

#include <queue>

#include <stdio.h>

#include <string.h>

#include <utility>

#include <algorithm>

using namespacestd;


#define MAXN 310

#define MAXM 10001

#define INF 30000100

#define min(a,b) (a)<(b)?(a):(b)


int d[MAXN][MAXN];

int V;

int N,M,T;

int sum;

int t[MAXM];


void warshall_floyd()

{

    for(int k=0;k<N;k++)

    {

        for(int i=0;i<N;i++)

        {

            for(int j=0;j<N;j++)

                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);

        }

    }

}




int main()

{

    while(cin>>N>>M)

    {

        

        if(N==0&&M==0)

            return0;

        

        for(int i=0;i<N;i++)

        {

            for(int j=0;j<N;j++)

            {

                if(i==j)

                    d[i][j]=0;

                else

                    d[i][j]=INF;

            }

        }

        

        for(int i=0;i<M;i++)

        {

            cin>>T;

            

            for(int j=0;j<T;j++)

            {

                cin>>t[j];

                t[j]--;

            }

            

            for(int j=0;j<T;j++)

            {

                for(int k=j+1;k<T;k++)

                {

                    d[t[j]][t[k]]=1;

                    d[t[k]][t[j]]=1;

                }

            }

        }

        

        warshall_floyd();

        

        int MIN=INF;

        

        for(int i=0;i<N;i++)

        {

            sum=0;

            for(int j=0;j<N;j++)

                sum+=d[i][j];

            if(sum<MIN)

                MIN=sum;

        }

        sum=MIN*100/(N-1);

        cout<<sum<<endl;

    }

    return 0;

}




POJ 3259

还是适合入门

至今觉得题目Two fields might be connected by more than one path. 这句话表达有问题,还以为输入的时候要判断两个点之间存较短的距离,

都打算用pair开始写了,然后发现可能是自己想太多了。还是找错误找到怀疑人生再见人生都用在找这些简单弱智的错误上了。


这道题目有一个坑就是路是双向的,要存两遍;虫洞是单向的,存一遍就好。只要判断存在负圈,即可输出YES。

还有不知道为什么MAXN要开到6000,不然会RE。


用到了Bellman-Ford算法,因为如果图中不存在负圈,那么最短路不会经过同一个顶点两次(即|V|-1 条边)。相反,如果存在负圈,那么第|N|次循环也会更新d的值,所以只要第|N|次循环更新了d的值,就存在负圈。


#include <iostream>

#include <algorithm>

using namespacestd;


#define MAXV 510

#define MAXM 6000

#define INF 50000000


struct edge

{

    int from,to,cost;

}es[MAXM];


int d[MAXV];

int F,N,M,W;

int f,t,c,w;

int top;


int bellman()

{

    int i,j;

    for(i=1;i<=N;i++)

        d[i]=INF;

    d[1]=0;

    for(i=1;i<=N;i++)

    {

        for(j=1;j<=top;j++)

        {

            edge e=es[j];

            if(d[e.from]!=INF&&d[e.to]>d[e.from]+e.cost)

            {

                d[e.to]=d[e.from]+e.cost;

                if(i==N)

                    return0;

            }

            

        }

    }

    return1;

}


int main()

{

    cin>>F;

    while(F--)

    {

        cin>>N>>M>>W;

        top=1;

        while(M--)

        {

            cin>>f>>t>>c;

            es[top].from=f;

            es[top].to=t;

            es[top].cost=c;

            top++;

            es[top].from=t;

            es[top].to=f;

            es[top].cost=c;

            top++;

            

        }

        while(W--)

        {

            cin>>es[top].from>>es[top].to>>w;

            es[top].cost=(-1)*w;

            top++;

        }

        if(bellman())

            cout<<"NO"<<endl;

        else

            cout<<"YES"<<endl;

    }

    return0;

}



POJ 3268

因为时间有点紧,觉得自己徒手打有难度

所以借鉴了网上的解题报告

http://www.hankcs.com/program/cpp/poj-3268-silver-cow-party.html


用到了Dijkstra算法,用优先队列较快找到最小值节省时间复杂度


思路很巧妙,把图反着也存一遍,那么就是从确定的一个点出发,求最短路径之和的最大值。

因为排序在+1的基础上不会处理,所以还是把农场-1存储了。

还有大神的排序方法也收下了


#include <iostream>

#include <algorithm>

#include <vector>

#include <queue>

using namespace std;



#define MAXV 1010

#define MAXE 100100

#define INF 100000000

struct edge

{

    int to,cost;

    edge(){}

    edge(int to,int cost):to(to),cost(cost){}

};

typedef pair<int,int> P;

//********

vector<vector<edge>> G(MAXV);

vector<vector<edge>> RG(MAXV);


int d[MAXV];

int rd[MAXV];

int V,E;


void dijkstra(int s)

{

    priority_queue<P,vector<P>,greater<P>>que;

    fill(d,d+V,INF);

    d[s]=0;

    que.push(P(0,s));

    

    while(!que.empty())

    {

        P p=que.top();

        que.pop();

        int v=p.second;

        if(d[v]<p.first)   continue;

        for(int i=0;i<G[v].size();i++)

        {

            edge e=G[v][i];

            if(d[e.to]>d[v]+e.cost)

            {

                d[e.to]=d[v]+e.cost;

                que.push(P(d[e.to],e.to));

            }

        }

    }

}


int main()

{

    int M,X;

    while(cin>>V>>M>>X)

    {

        X--;

        while(M--)

        {

            int A,B,T;

            cin>>A>>B>>T;

            A--;B--;

            G[A].push_back(edge(B,T));

            //vector尾部加入一个数据

            RG[B].push_back(edge(A,T));

        }

        dijkstra(X);

        G=RG;

        //********

        memcpy(rd,d,sizeof(d));

        dijkstra(X);

        for(int i=0;i<V;i++)

            d[i]+=rd[i];

        //sort(d,d+V);

        //cout<<d[V-1]<<endl;

        //V++;

        cout << *max_element(d,d+V) << endl;

    }

    return 0;

}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值