洛谷——图论

1.P1027 Car的旅行路线

题目描述

又到暑假了,住在城市A的Car想和朋友一起去城市B旅游。她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I个城市中高速铁路了的单位里程价格为Ti,任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为t。

图例(从上而下)

机场 高速铁路

飞机航线

  注意:图中并没有

标出所有的铁路与航线。

那么Car应如何安排到城市B的路线才能尽可能的节省花费呢?她发现这并不是一个简单的问题,于是她来向你请教。

找出一条从城市A到B的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。

输入输出格式

输入格式:

第一行为一个正整数n(0<=n<=10),表示有n组测试数据。

每组的第一行有四个正整数s,t,A,B。

S(0<S<=100)表示城市的个数,t表示飞机单位里程的价格,A,B分别为城市A,B的序号,(1<=A,B<=S)。

接下来有S行,其中第I行均有7个正整数xi1,yi1,xi2,yi2,xi3,yi3,Ti,这当中的(xi1,yi1),(xi2,yi2),(xi3,yi3)分别是第I个城市中任意三个机场的坐标,T I为第I个城市高速铁路单位里程的价格。

输出格式:

共有n行,每行一个数据对应测试数据。 保留一位小数

输入输出样例

输入样例#1:
1
3 10 1 3
1 1 1 3 3 1 30
2 5 7 4 5 2 1
8 6 8 8 11 6 3
输出样例#1:
47.5
思路:
  此题的难点在于求第四个点和记录话费上,至于如何求,运用数学方法(看代码)。。。
  图论的部分Floyed就可以了。。。
#^_^# 代码:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

const int N = 803;
int n,s,t,A,B,xi[N],yi[N],ti[N];
double d[N][N];

void spend(int t1,int t2) {  //求花费 
    d[t1][t2]=sqrt((xi[t1]-xi[t2])*(xi[t1]-xi[t2])+(yi[t1]-yi[t2])*(yi[t1]-yi[t2]));//求图上距离!? 
    if(((t1-1)/4)==((t2-1)/4)) //判断两点是否在同一个城市中 
        d[t1][t2]=d[t1][t2]*ti[(t1-1)/4+1];//在同一个城市中坐高铁 
    else 
        d[t1][t2]=d[t1][t2]*t;//不在同一个城市中坐飞机 
    d[t2][t1]=d[t1][t2];//从A到B和从B到A距离相同 
    return ;
}

int Find_third(int t1,int t2, int t3) {  //寻找直角三角形直角所在的点,此点的所对点即为第四个点 
    //寻找方法为数学方法,在直角三角形中,斜边最长,不在斜边上的点就为直角所在点 
    if((d[t1][t2]>d[t2][t3])&&(d[t1][t2]>d[t3][t1])) return t3;
    if((d[t3][t1]>d[t1][t2])&&(d[t3][t1]>d[t2][t3])) return t2;
    if((d[t2][t3]>d[t3][t1])&&(d[t2][t3]>d[t1][t2])) return t1;
}

void Calc_third(int t1,int t2,int t3) {
    spend(t1,t2); //计算出花费,找第四条边 
    spend(t3,t1);
    spend(t2,t3);
    int Third=Find_third(t1,t2,t3);
    if(Third==t1){ 
        xi[t3+1]=xi[t3]+xi[t2]-xi[t1];
        yi[t3+1]=yi[t3]+yi[t2]-yi[t1];
    }
    else if(Third==t2) {
        xi[t3+1]=xi[t3]+xi[t1]-xi[t2];
        yi[t3+1]=yi[t3]+yi[t1]-yi[t2];
    }
    else if(Third==t3) {
        xi[t3+1]=xi[t1]+xi[t2]-xi[t3];
        yi[t3+1]=yi[t1]+yi[t2]-yi[t3];
    }
}

int main() {
    cin>>n;
    for(int i=1; i<=n; i++)
    {
        cin>>s>>t>>A>>B;
        for(int i=1; i<=401; i++) //初始化 
            for(int j=1; j<=401; j++) 
                d[i][j]=0x7fffffff;
        for(int i=1; i<=s; i++) {
            cin>>xi[i*4-3]>>yi[i*4-3]>>xi[i*4-2]>>yi[i*4-2]>>xi[i*4-1]>>yi[i*4-1]>>ti[i]; //为什么要i*4-3,i*4-2,i*4-1呢??
            //小技巧,前三条边的坐标依次存输入在数组中,将第四个位置空下,等后来存放第四条边的坐标 
            Calc_third(i*4-3,i*4-2,i*4-1); //寻找第四条边 
        }
        for(int i=1; i<=4*s; i++) //将所有边都找完以后,重新计算花费记录下来,寻找答案 
            for(int j=1; j<=4*s; j++) 
                spend(i,j);
        for(int k=1; k<=4*s; k++) //Floyed 
            for(int i=1; i<=4*s; i++)
                for(int j=1; j<=4*s; j++)
                    if(d[i][k]+d[k][j]<d[i][j])
                        d[i][j]=d[i][k]+d[k][j];
        double ans=3456789.0;
        for(int i=4*A-3; i<=4*A; i++)
            for(int j=4*B-3; j<=4*B; j++) 
                if(ans>d[i][j]) //找最小值 
                    ans=d[i][j];
        printf("%.1lf
",ans);
    }
    return 0;
}

2.P1629 邮递员送信

题目描述

有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要一定的时间。这个邮递员每次只能带一样东西。求送完这N-1样东西并且最终回到邮局最少需要多少时间。

输入输出格式

输入格式:

第一行包括两个整数N和M。

第2到第M+1行,每行三个数字U、V、W,表示从A到B有一条需要W时间的道路。 满足1<=U,V<=N,1<=W<=10000,输入保证任意两点都能互相到达。

【数据规模】

对于30%的数据,有1≤N≤200;

对于100%的数据,有1≤N≤1000,1≤M≤100000。

输出格式:

输出仅一行,包含一个整数,为最少需要的时间。

输入输出样例

输入样例#1:
5 10
2 3 5
1 5 5
3 5 6
1 2 8
1 3 8
5 3 4
4 1 8
4 5 3
3 5 6
5 4 2
输出样例#1:
83
思路:
  因为邮递员送和回都要计算,所以跑两遍SPFA,而且一次只能拿一件,所以答案就是从邮局到所有点的最短路的和,(累加)。
  注意边数组一定要开大!!!
#^_^# 代码:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;

queue<int>q;
const int N=1003;
const int M=100003;
struct Edge{
    int pre; int to; int w;
}edge[M*4];
int u[M],v[M],w[M];

struct edge{
    int to;int l;
}dl[N][N];

int n,m,num_edge,head[M],vis[M],dis[M],sum;

void build(int u,int v,int w) {
    edge[++num_edge].pre = head[u];
    edge[num_edge].to = v;
    edge[num_edge].w = w;
    head[u] = num_edge;
}

void SPFA() {
    while(!q.empty()) q.pop();
    memset(dis,0x7f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    vis[1]=1;
    dis[1]=0;
    q.push(1);
    while(!q.empty()) {
        int s=q.front();
        q.pop();
        vis[s]=0;
        for(int i=head[s]; i; i=edge[i].pre) {
            int to=edge[i].to;
            if(dis[s]+edge[i].w<dis[to]) {
                dis[to]=dis[s]+edge[i].w;
                if(!vis[to]) {
                    vis[to]=1;
                    q.push(to); 
                }
            }
        }
    }
    for(int i=2; i<=n; i++) 
       sum+=dis[i];
}

int main() {
    scanf("%d%d",&n,&m);
    for(int i=1; i<=m; i++) {
        scanf("%d%d%d",&u[i],&v[i],&w[i]);
        build(u[i],v[i],w[i]);
    }
    SPFA();
    memset(edge,0,sizeof(edge));
    memset(head,0,sizeof(head));
    for(int i=1; i<=m; i++) {
        build(v[i],u[i],w[i]);
    }
    SPFA();
    cout<<sum<<endl;
    return 0;
}

自己选的路,跪着也要走完!!!
原文地址:https://www.cnblogs.com/wsdestdq/p/6862304.html