【最小路径】

来源:互联网 发布:知乎看见了女朋友 编辑:程序博客网 时间:2024/05/19 13:23
/*POJ 3268题目大意是给出一个有向图的带权邻接矩阵,然后给定目标节点X,求出其余结点出发到结点X再从X回到出发结点的最短路径和中最大的那个...把矩阵转置一下就好了,转置以后就又相当于从X出发了,再来一次Dijkstra搞定...很好理解的..*/#include<cstdio>#include<cstring>using namespace std;const int N=1010;const int MAX=1000001;int n,m;int map1[N][N];int map2[N][N],visited[N];int dist1[N],dist2[N];void dijkstra(int mapx[][N],int dist[],int x){//最短路径    int u,minx;    for(int i=1;i<=n;i++)        dist[i]=mapx[x][i];    memset(visited,0,sizeof(visited));    visited[x]=1;    for(int i=1;i<=n;i++){        u=x,minx=MAX;        for(int j=1;j<=n;j++){            if(!visited[j]&&dist[j]<minx){                minx=dist[j];                u=j;            }        }        visited[u]=1;        for(int j=1;j<=n;j++){            if(!visited[j]&&dist[j]>dist[u]+mapx[u][j])                dist[j]=dist[u]+mapx[u][j];        }    }}int main(){    int ai,bi,ti,x;    int ans=0;    scanf("%d%d%d",&n,&m,&x);    for(int i=1;i<=n;i++){//初始化        for(int j=1;j<=n;j++){             if(i==j)                {                    map1[i][j]=0;                    map2[j][i]=0;                }                else                {                    map1[i][j]=MAX;                    map2[j][i]=MAX;                }        }    }    for(int i=1;i<=m;i++){        scanf("%d%d%d",&ai,&bi,&ti);        map1[ai][bi]=ti;        map2[bi][ai]=ti;//转置矩阵    }    dijkstra(map1,dist1,x);    dijkstra(map2,dist2,x);    for(int i=1;i<=n;i++){        if(ans<dist1[i]+dist2[i])            ans=dist1[i]+dist2[i];    }    printf("%d\n",ans);}



/*题目要我们求是否存在一条路,FJ重新回到起点之后时间回到了过去,就是让我们判断在图中是否存在负权回路。我用了SPFA,当一个点入队超过n次时,可以判断图中存在负权回路。注意图中的前m条路是双向的,注意处理后面的w条虫洞是单向的。POJ 3259*/#include<cstdio>#include<queue>#include<vector>#include<algorithm>using namespace std;#define MAXN 550#define INF 0x7fffffffstruct node{    int to;//终点    int dis;//距离};bool in[MAXN];//是否在队列int counts[MAXN],dis[MAXN],n,m,w;// counts入队的次数、dis最短的距离vector<node>g[MAXN];bool spfa(int s){//模板题    queue<int>q;    for(int i=1;i<=n;i++){        dis[i]=INF;        counts[i]=0;        in[i]=false;    }    dis[s]=0;    counts[s]=1;    in[s]=true;    q.push(s);    while(!q.empty()){        int tag=q.front();        q.pop();        in[tag]=false;        for(int i=0;i<g[tag].size();i++){            int j=g[tag][i].to;            if(g[tag][i].dis+dis[tag]<dis[j]){//更新路径                dis[j]=g[tag][i].dis+dis[tag];                if(!in[j]){//不在队列入队                    in[j]=true;                    counts[j]++;                    if(counts[j]>=n)//存在负环路                        return false;                    q.push(j);                }            }        }    }    return true;}void init(){  //初始化数据    scanf("%d%d%d",&n,&m,&w);    int x,y,d;    node temp;    for(int i=0;i<=n;i++)//清空操作        g[i].clear();    for(int i=1;i<=m;i++){        scanf("%d%d%d",&x,&y,&d);//双向边        temp.to=y;        temp.dis=d;        g[x].push_back(temp);        temp.to=x;        g[y].push_back(temp);    }    for(int i=1;i<=w;i++){        scanf("%d%d%d",&x,&y,&d);//单向边 只能回到过去        temp.to=y;        temp.dis=-d;        g[x].push_back(temp);    }}int main(){    int t ;    scanf("%d",&t);    while(t--){        init();        if(spfa(1))            printf("NO\n");        else            printf("YES\n");    }}

/*POJ 2139N头牛,拍了M部电影,同一部电影中的搭档们距离1,求最小度数之和。题解:flyod最短路,枚举找最小warshall_floyd算法,求任意两点间的最短路 O(V^3)dp[i][j] = e(i, j)的权值(不存在为Inf,dp[i][i] = 0)*/#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int inf=0x3f3f3f3f;int n,m,dp[303][303];void warshall_floyd(){  //模板    for(int k=1;k<=n;k++)        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++)                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);}int main(){      int ans=inf;    scanf("%d%d",&n,&m);    //初始化    memset(dp,inf,sizeof(dp));    for(int i=1;i<n;i++)        dp[i][i]=0;    while(m--){        int a,b[303];        scanf("%d",&a);    for(int i=0;i<a;i++)        scanf("%d",&b[i]);    for(int i=0;i<a-1;i++)        for(int j=i+1;j<a;j++){            dp[b[i]][b[j]]=dp[b[j]][b[i]]=1;        }    }    warshall_floyd();    for(int i=1;i<=n;i++){//枚举类型        int sum=0;        for(int j=1;j<=n;j++)        sum+=dp[i][j];        ans=min(ans,sum);    }    printf("%d\n",ans*100/(n-1));}

/*POJ 1062最短路径——Dijkstra算法此题的关键在于等级限制的处理,最好的办法是采用枚举,即假设酋长等级为5,等级限制为2,那么需要枚举等级从3~5,4~6,5~7从满足改等级范围的结点组成的子图中用Dijkstra来算出最短路径小结,通过枚举的方式可以消除一些图与图之间的限制[lev-M,lev],[lev-M+1,lev+1],... ...,[lev,lev+M]*/#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define INF 0x3f3f3f3f#define MAXN 101using namespace std;int dict[MAXN][MAXN],lev[MAXN],d[MAXN],value[MAXN];bool within_lim[MAXN],v[MAXN];//within_lim为满足等级限制的标记数组int lev_lim,n;int dijkstra(){    int mininum=INF;    memset(v,0,sizeof(v));//清除所有点的标号    for(int i=1;i<=n;i++)//设d[0] = 0,其他d[i] = INF        d[i]=(i==1?0:INF);    for(int i=1;i<=n;i++){//循环N次        int x=0,m=INF;        for(int j=1;j<=n;j++){            if(!v[j]&&d[j]<=m&&within_lim[j]){//在所有未标号且满足等级限制的结点中,选出d值最小的结点x                x=j;                m=d[j];            }        }        v[x]=1;//给结点x标记        for(int j=1;j<=n;j++){            if(within_lim[j]){//对于从x出发的所有边(x,y),更新d[y] = min{d[y], d[x] + map[x][y])                d[j]=min(d[j],d[x]+dict[x][j]);//满足等级限制            }        }    }    for(int i=1;i<=n;i++){        d[i]+=value[i];        if(d[i]<mininum)//对于每个d[i]值,还需加上进入该结点的花费,再进行比较            mininum=d[i];    }    return mininum;}int main(){    scanf("%d%d",&lev_lim,&n);    for(int i=0;i<=n;i++)        for(int j=0;j<=n;j++)            dict[i][j]=(i==j?0:INF);//图的初始化,注意对角线初始化为0,从自己出发到自己的花费为0    for(int i=1;i<=n;i++){        int t;        scanf("%d%d%d",&value[i],&lev[i],&t);        for(int j=1;j<=t;j++){            int k;            scanf("%d",&k);            scanf("%d",&dict[i][k]);        }//建图完毕    }    int kinglev=lev[1];    int min_cost=INF,cost;    for(int i=0;i<=lev_lim;i++){        memset(within_lim,0,sizeof(within_lim));//初始化标记数组        for(int j=1;j<=n;j++){//枚举等级允许范围的结点            if(lev[j]>=kinglev-lev_lim+i&&lev[j]<=kinglev+i)                within_lim[j]=1;        }        cost=dijkstra();        if(cost<min_cost)            min_cost=cost;    }    printf("%d\n",min_cost);}

/*POJ  2240*/#include<cstdio>#include<map>#include<string>#define INF 0x3f3f3f3fusing namespace std;char money[30];char change1[30],change2[30];double trans;double dict[50][50];int n,m;map<string,int>p;//用map建立字符串与编号之间的关系(巧用)void Floyd(){    for(int k=1;k<=n;k++)        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++){                if(dict[i][j]<dict[i][k]*dict[k][j])   //变形的最大路径  把‘+’变为了‘*’                    dict[i][j]=dict[i][k]*dict[k][j];    }}void solve(){    int cnt=1;    while(~scanf("%d%*c",&n)&&n){        for(int i=1;i<=n;i++){            scanf("%s",money);            p[money]=i;            dict[i][i]=1;        }        scanf("%d%*c",&m);        for(int i=1;i<=m;i++){            scanf("%s%lf%s",change1,&trans,change2);            dict[p[change1]][p[change2]]=trans;        }        Floyd();        bool flag=false;        for(int i=1;i<=n;i++){            if(dict[i][i]>1){                flag=true;                break;            }        }         if(flag)        {            printf("Case %d: Yes\n", cnt++);        }        else        {            printf("Case %d: No\n", cnt++);        }    }}int main(){    solve();    return 0;}

/*POJ  1860题意 : 就是套汇的问题,汇率Rab, 增加了一个手续费  Cab 。。。。。。。每次的结果是  (本金 - 手续费) * 汇率,而且一个人拥有的钱的类型是已知的,拥有的value 钱的个数也是已知的, 问你能不能增值。输入 :3 2 1 20.0                         //钱种类个数  汇率的个数,拥有第几种钱, 拥有多少钱1 2 1.00 1.00 1.00 1.00            //钱a, 钱b, rab, cab, rba, cba2 3 1.10 1.00 1.10 1.00*/#include<cstdio>#include<cstring>#include<algorithm>using namespace std;struct Edge{    int s,e;    double r;    double c;}edge[210];int k;int N,M,S;double V;double dis[110];bool bellman_ford(){    bool sign;    memset(dis,0,sizeof(dis));    dis[S]=V;    for(int j=0;j<N+1;j++){//N+1 如果每次都有改变的话,说明一定存在环路。        sign=false;        for(int i=0;i<k;i++){            if(dis[edge[i].e]<(dis[edge[i].s]-edge[i].c)*edge[i].r){                 dis[edge[i].e]=(dis[edge[i].s]-edge[i].c)*edge[i].r;                 sign=true;            }        }        if(!sign)            break;    }    if(sign)        return false;    else        return true;}int main(){    while(~scanf("%d%d%d%lf",&N,&M,&S,&V)){        k=0;        int a,b;        double rab,cab,rba,cba;        for(int i=0;i<M;i++){            scanf("%d%d%lf%lf%lf%lf",&a,&b,&rab,&cab,&rba,&cba);            edge[k].s=a;            edge[k].e=b;            edge[k].r=rab;            edge[k++].c=cab;            edge[k].s=b;            edge[k].e=a;            edge[k].r=rba;            edge[k++].c=cba;        }        if(bellman_ford())            puts("NO");        else            puts("YES");    }}

/*POJ  2253//如果存在路径,则选择路径中最长的边来更新即可*/#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>using namespace std;const int maxn=210;const double MAX=2000;double dict[maxn][maxn];double dis[maxn];int visited[maxn];int n;double ans;struct Point{    double x,y;}p[maxn];double dist(Point a,Point b){   return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));}void Dijkstra(){    for(int i=1;i<=n;i++)        dis[i]=MAX;    dis[1]=0;    memset(visited,0,sizeof(visited));    for(int i=1;i<=n;i++){        int x;        double minx=MAX;        for(int j=1;j<=n;j++){            if(!visited[j]&&dis[j]<=minx){                minx=dis[j];                x=j;            }        }        visited[x]=1;        if(ans<dis[x]&&dis[x]!=MAX)            ans=dis[x];        if(x==2)            return ;        for(int j=1;j<=n;j++){            if(!visited[j])                dis[j]=min(dis[j],dict[x][j]);        }    }}int main(){    int kcase=0;    while(scanf("%d",&n),n){        for(int i=1;i<=n;i++)            scanf("%lf%lf",&p[i].x,&p[i].y);        for(int i=1;i<=n;i++){            dict[i][i]=0;            for(int j=i+1;j<=n;j++){                 dict[i][j] = dist(p[i],p[j]);                dict[j][i] = dist(p[i],p[j]);            }        }        ans=0;        Dijkstra();         printf("Scenario #%d\n", ++kcase);        printf("Frog Distance = %.3lf\n\n", ans);    }}


0 0
原创粉丝点击