UPC训练第23场——寻路——弗洛伊德

题目描述
明明同学被困在一个荒凉的北极岛屿,他可以用小船乘着海流用1单位时间从一个岛移动到另一个岛。他得到了一个海洋地图,有N(1<=N<=100)条单向海流航线,编号为1…N。
告诉你他的起始位置M(1<=M<=N)和地图,请编程帮助明明确定到达每个岛的最短时间是多少。
输入为一个矩阵C,第r行,第c列的值若为1,则r到c存在海流,值为0则不存在海流。
输入
第1行:两个用空格隔开的整数:N和M
第2…N+1:第i+1行包含N个用空格隔开的整数:C_R
输出
第1…??行:第一行输出M,第i+1行包含时刻i能到达的岛屿(升序排列)
样例输入

4 1 
0 1 0 1 
0 0 1 0 
0 0 0 1 
0 0 0 0

样例输出

1
2 4
3

当时做这个题的时候,可以感觉出考点是弗洛伊德全源最短路问题,但是死活没明白样例是什么意思,于是乎卡了好像时间,先介绍一下题目的意思叭。

给出的矩阵表达的意思是如果第 i 行,第 j 列是1,那么说明可以从 i 到达 j 。如果是0的话,那么就说明无法从 i 到 j 。 而给出的起点 m 可以看做是第几行的开始。拿样例来说,1,2为1,说明可以从1->2; 1,4为1,可以说明可以从1->4,两个需要的时间都是 1 。而要是从1->3 那么来说需要从1->2,2->3,两步来完成,耗时为2(样例第二行可以看出能够从2->3).
输出情况就是先输出耗时短可以到达的岛屿,往下是耗时比较长的岛屿,如果好耗时相同,那么来说就需要从编号从小到大进行输出,比如耗时为1的可以从1到达的岛屿有24,先输出2,在输出4.
一上来就看懂题的巨巨可以忽略以上的题目解释

下面将附上本人的两种方法,两种方法都是可行的(根本都是一样的就只是用的vector方式不太一样罢了),但是之前一种方法因为一个条件把自己卡的死死的。伤心
想要很好了解vector的小伙伴可以通过以下的链接来进行学习~~(巨佬请忽略)~~

传送门1

传送门2

传送门3

方法一

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define wuyt main
typedef long long ll;
#define HEAP(...) priority_queue<__VA_ARGS__ >
#define heap(...) priority_queue<__VA_ARGS__,vector<__VA_ARGS__ >,greater<__VA_ARGS__ > >
template<class T> inline T min(T &x,const T &y){return x>y?y:x;}
template<class T> inline T max(T &x,const T &y){return x<y?y:x;}
///#define getchar()(p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
///char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf;
ll read(){ll c = getchar(),Nig = 1,x = 0;while(!isdigit(c) && c!='-')c = getchar();
if(c == '-')Nig = -1,c = getchar();
while(isdigit(c))x = ((x<<1) + (x<<3)) + (c^'0'),c = getchar();
return Nig*x;}
#define read read()
const ll inf = 1e15;
const ll INF = 0x3f3f3f3f;
const int maxn = 2e6 + 7;
const int mod = 1e9 + 7;
ll maxx=-1;
ll minn=inf;
ll num[1008];
ll dis[1008][1008];
ll num2[maxn];
ll res,ans;
map<string,ll> mp;
priority_queue <int ,vector<int> ,greater<int> > xiaogen;
bool cmp(ll a,ll b){
    return a>b;
}
queue <ll> duilie;
queue <ll> cnt;
vector <ll> vet;
int main()
{
    int n=read,m=read;
    for(int i=1;i<=n;i++){///初始化操作,将从自己到自己的时间设置成0
        for(int j=1;j<=n;j++){
            if(i==j) dis[i][j]=0;
            else dis[i][j]=mod;///其余设置成比较大的模数
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int a=read;
            if(a==0) continue;/// 如果是0那就说明两点不同就不再理会直接跳过
            else if(a==1) dis[i][j]=1;
        }
        dis[i][i]=0;///为了保险还是要将这里改成0,数据没问题应给可以不用加,但是本蒟蒻没有尝试
    }
    for(int k=1;k<=n;k++){/// 弗洛伊德三层for
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(dis[i][j]>dis[i][k]+dis[k][j])
                    dis[i][j]=dis[i][k]+dis[k][j];
            }
        }
    }
    /// 按照题目要求进行输出
    cout<<m<<endl;
    for(int i=1;i<=n;i++){
            ll temp=dis[m][i];
            num[i]=temp;
            if(temp==mod) temp=0;/// 划重点!91%卡在了这里
            vet.push_back(temp);
    }
    /// 排序去重
    sort(vet.begin(),vet.end());
    vet.erase(unique(vet.begin(),vet.end()),vet.end());
    int len=vet.size();/// 检测vector中存放了多少个数
    for(int i=1;i<=len-1;i++){
        for(int j=1;j<=n;j++){
            if(vet[i]==num[j]){///对应相等输出对应的编号
                printf("%d ",j);
            }
        }
        puts("");
    }
    return 0;
}

warning

  for(int i=1;i<=n;i++){
            ll temp=dis[m][i];
            num[i]=temp;
            if(temp==mod) temp=0;/// 划重点!91%卡在了这里
            vet.push_back(temp);
    }

在这里如果两点行不通的情况下不排除,将会卡在91%,亲测有效
在这里本蒟蒻优化了一下,将行不通的情况那个临时变量temp 变成0,这样一来就会将和自身到自身的那个0在后面去重掉,将不影响最终结果

方法2

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define wuyt main
typedef long long ll;
#define HEAP(...) priority_queue<__VA_ARGS__ >
#define heap(...) priority_queue<__VA_ARGS__,vector<__VA_ARGS__ >,greater<__VA_ARGS__ > >
template<class T> inline T min(T &x,const T &y){return x>y?y:x;}
template<class T> inline T max(T &x,const T &y){return x<y?y:x;}
///#define getchar()(p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
///char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf;
ll read(){ll c = getchar(),Nig = 1,x = 0;while(!isdigit(c) && c!='-')c = getchar();
if(c == '-')Nig = -1,c = getchar();
while(isdigit(c))x = ((x<<1) + (x<<3)) + (c^'0'),c = getchar();
return Nig*x;}
#define read read()
const ll inf = 1e15;
const ll INF = 0x3f3f3f3f;
const int maxn = 2e6 + 7;
const int mod = 1e9 + 7;
ll maxx=-1;
ll minn=inf;
ll num[1008];
ll dis[1008][1008];
ll num2[maxn];
ll res,ans;
map<string,ll> mp;
priority_queue <int ,vector<int> ,greater<int> > xiaogen;
bool cmp(ll a,ll b){
    return a>b;
}
queue <ll> duilie;
queue <ll> cnt;
vector <ll> vet[maxn];
int main()
{
    int n=read,m=read;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==j) dis[i][j]=0;
            else dis[i][j]=mod;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int a=read;
            if(a==0) continue;
            else if(a==1&&i!=j) dis[i][j]=1;
        }
        dis[i][i]=0;
    }
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(dis[i][j]>dis[i][k]+dis[k][j])
                    dis[i][j]=dis[i][k]+dis[k][j];
            }
        }
    }
    cout<<m<<endl;
    for(int i=1;i<=n;i++){
        if(i!=m&&dis[m][i]!=mod){
            ll temp=dis[m][i];
            maxx=max(maxx,temp);
            vet[temp].push_back(i);
        }
    }
    for(int i=1;i<=maxx;i++){
        for(auto tmp:vet[i]) cout<<tmp<<" ";
        printf("\n");
    }
    return 0;
}

和第一种方式不同的只有这一点,但是第一次使用这种方式过的,不容易忘记条件,但是说实话,本蒟蒻驾驭不了这种使用vector的方式,看的到这种方法真的是眼前一亮

	/// 前面声明的时候一定要记得加上想要申请的vector的大小
	/// 例如: vector  vet[maxn];
    cout<<m<<endl;
    for(int i=1;i<=n;i++){
        if(i!=m&&dis[m][i]!=mod){
            ll temp=dis[m][i];
            maxx=max(maxx,temp);
            vet[temp].push_back(i);
        }
    }
    for(int i=1;i<=maxx;i++){
        for(auto tmp:vet[i]) cout<<tmp<<" ";
        printf("\n");
    }

以上便是对本题的相关阐述
点个赞再走嘛

你可能感兴趣的:(图论)