1 条题解

  • 0
    @ 2019-11-08 19:35:59

    老师给的数据是过了的,我也是看的题解才会的

    #include<iostream>// 用Dijkstra进行搜索
    #include<cstdio>
    #define M 1000000
    //没必要让最大值为INT_MAX,比所有答案大就行,也方便运算
    #define M2 210
    //205,208,201,200 刚刚要超时 老师说是电脑问题
    using namespace std;
    int n,m,a,b,f[M2][M2],dp[M2][M2];//dp[a][b]表示状态(a,b),即1->a->b->1经历的最少点数,当然a可以等于b;而这里我指的是a->2->2->b的最少点数
    bool v[M2][M2];//标记状态(a,b)是否被更新
    int main()
    {
    //freopen("president.in","r",stdin);
    //freopen("president.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)//定义距离数组
    for(int j=0;j<n;j++)//没必要用memset()定义 ,老实写,踏实些
    f[i][j]=(i==j?0:M);//这道题中ij相同指的是同一点,距离自然为零
    for(int i=1;i<=m;i++)
    {
    scanf("%d%d",&a,&b);//将数组整体向左上移动一下,方便理解计数,节约两排空间,目标状态就变成了dp[0][0]
    f[--a][--b]=1;//有边距离定义为1,可理解为到得了这个点
    }
    for(int k=0;k<n;k++)
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    f[i][j]=min(f[i][j],f[i][k]+f[k][j]);//Floyd求任意两点距离
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    dp[i][j]=M;//定义初始状态,为最大值
    dp[1][1]=1;//定义初始状态(1,1)为1,平移前,实际上也就是(2,2);以它为初始状态保证了每一个状态由它更新,[当然走不到的点自然不行];
    while(1)//死循环一枚,貌似f(;;)快一些 ||不断找出未使用过的最少状态,用其更新全部状态【用Dijkstra搜索目标状态】,上一行已经保证了全部更新的状态都经过2
    {//题目暗含了必定有解,所以不会真的死循环
    a=-1,b=-1;//初始的奇怪边
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    if(!v[i][j]&&(a==-1||dp[i][j]<dp[a][b])) a=i,b=j;//找目前未使用的最少状态
    if(a==0&&b==0) break;//找到目标状态退出循环
    v[a][b]=1;//标记
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    if(i!=b&&i!=a&&j!=a&&j!=b)//更新时,不能与当前状态有重合
    dp[i][j]=min(dp[i][j],dp[a][b]+f[b][i]+f[i][j]+f[j][a]-1);//状态转移,更新i->...->j的最少点,记得减去本身的1;重复的点随即被更新去掉【二维,Dijkstra,用最优状态更新、搜索】

    }
    printf("%d",dp[0][0]);

    return 0;
    }

  • 1

信息

难度
10
分类
(无)
标签
(无)
递交数
1
已通过
0
通过率
0%
上传者