poj-1797

//23108K    4250MS  Java
#include <stdio.h>
#include <string.h>

#define UNREACH 0
    // private static final long INF = -1;
#define MAX 1500
int sCrossingNum;
int processedFlag[MAX];
char djFlag[MAX];
int streetWeightInfo[MAX][MAX];

void reset() {
    sCrossingNum = 0;
    // for (int i = 0; i < MAX; i++) {
    //     processedFlag[i] = 0;
    //     djFlag[i] = 0;
    //     for (int j = 0; j < MAX; j++) {
    //         streetWeightInfo[i][j] = UNREACH;
    //     }
    // }
    memset(processedFlag, 0, sizeof(processedFlag));
    memset(djFlag, 0, sizeof(djFlag));
    memset(streetWeightInfo, 0, sizeof(streetWeightInfo));
}

// int dj(int beginNodeId) {
//     int i,j,u = 0;
//     int temp;
//     for (i = 0; i < sCrossingNum; i++) {
//         processedFlag[i] = streetWeightInfo[beginNodeId][i];
//         djFlag[i] = 0;
//     }
//     djFlag[beginNodeId] = 1; // beginNode is processed

//     for(j = 1; j < sCrossingNum; ++j) // process left Nodes, total sCrossingNum - 1
//     {
//         temp = 0;
//         for(i = 0; i < sCrossingNum; ++i) { // fins the most weight
//             if(!djFlag[i] && processedFlag[i] > temp)
//             {
//                 temp = processedFlag[i];
//                 u = i;
//             }
//         }
       
//         djFlag[u] = 1;

//         for(i = 0; i < sCrossingNum; ++i) // update the adjacent code
//         {
//             if(!djFlag[i] && streetWeightInfo[u][i] > 0)
//             {
//                 temp = processedFlag[u] < streetWeightInfo[u][i] ? processedFlag[u] : streetWeightInfo[u][i];//本条路径的瓶颈或者更小
//                 if(temp > processedFlag[i]) {
//                     processedFlag[i] = temp;
//                 }
//             }
//         }
//     }
//     return processedFlag[sCrossingNum-1];
// }

int min(int a,int b)
{
  return a<b? a:b;
}

int dijkstra(int cross);

// void getMostWeight(int caseId) {
//     // long mostWeight = 0;
//     // if (sCrossingNum == 1) { // if only one crossing, no need consider weight
//     //     mostWeight = streetWeightInfo[0][0];
//     // } else {
//     // int mostWeight = dj(0); // begin from hugo
//     int mostWeight = dijkstra(sCrossingNum);
//     // }
//     // printf("Scenario #%d:\n", caseId);
//     // printf("%d\n\n", mostWeight);
// }

int dijkstra(int cross)
{
   int i,j,u,temp;
   for(i = 1 ; i <= cross ; ++i)
   {
         processedFlag[i] = streetWeightInfo[1][i];
         djFlag[i] = 0;
   }
    
   djFlag[1] = 1;//起点进入集合
    
    for(j = 1 ; j < cross ; ++j)
    {
      temp = 0;
      for(i = 1 ; i <= cross ; ++i)
      if(!djFlag[i] && processedFlag[i] > temp)//要选出最大的载重
      {
         temp = processedFlag[i];
         u = i ;
      }     
       
      djFlag[u] = 1;
       
      /*  刷新  */
      for(i = 1 ; i <= cross ; ++i)
      {
         if(!djFlag[i] && streetWeightInfo[u][i])
         {
            temp = min(processedFlag[u],streetWeightInfo[u][i]);//本条路径的瓶颈或者更小
           if(temp > processedFlag[i])//说明可以增大载重
            processedFlag[i] = temp;           
         }
      }   
           
    }//for(j)   
 
    return processedFlag[cross];
}

// void solve(int caseId) {
//     getMostWeight(caseId);
//     reset();
// }



int main() {
    int caseNum;
    scanf("%d", &caseNum);
    for (int i = 1; i <= caseNum; i++) {
        reset();
        int streetNum;
        scanf("%d%d", &sCrossingNum, &streetNum);
        for (int j = 0; j < streetNum; j++) {
            int from;
            int end;
            int weight;
            scanf("%d%d%d", &from, &end, &weight);
            streetWeightInfo[from][end] = weight;
            streetWeightInfo[end][from] = weight;
        }
        printf("Scenario #%d:\n",i);
        printf("%d\n\n",dijkstra(sCrossingNum));
        // solve(i);
    }
}


23108K    4250MS  Java,

java够慢。。同样逻辑的C 300多ms....

极坑的一题 囧.

先用了DFS,结果TLE。

后来尝试了DJ算法的变种,后来发现自己记的DJ算法步骤根本不对。。。。

在改成了正确的DJ以后,还是WA,估计前后贡献了十几次。。。。

后来在看别人的code的时候,才发现 自己把双向图当成单向图搞了.......

题目说是两个cross A B直接有street,那么这个street确实应该是双向的通路,做有向图做惯了,只给了A->B, B->A给搞成不可达了。。。会AC才怪

能找到的测试数据也没发现这个错误。。。 哎,归根到底还是自己的问题,妈的以后,要牢记了,只要没说是单向,那样就必然双向.

先整一下DJ算法的步骤,深化一下:

DJ会把点分成两类:一类V1是已经求出了到起始点B最短路径的,令一类V2则是还没有求出最短路径的点(也会有到B的路径长度,但是该长度还不是真正的最短路径长度)。

一开始V1里只有一个点,及起始点B,这时候要搞两个数组:

F 用来记录某个点是否属于V1(true),否则就是V2(false)

D用来记录当前所有点到B的最短路径的长度。

最开始,要遍历B的所有边,如果和某个点 N 相通,就在D[N]中记录下来此路径的长度,不相通给一个合适的不相通表示值。

这次遍历完以后,F[B]置为true,来标示B已经在V1中,

然后开始遍历所有的点,找到一个离B的最短路径的长度最小并且还不在V1中的点T,T此时的最短路径L一定已经是到B的最短路径了(反证法,假定这时候T 还有别的更短路径可以到达B, 但是因为B的其他所有通路的长度都比L还长(L1......LN > L),其他的路径必然会经过其他路径的某一条,那么在所有的边权值 >= 0的情况下,必然新的最短路径是绝不可能比L还小的(L1/L2/../LN + 非负数, 必然还大大于L),因此,必然已经最短的路径,可以直接加入到V1中)

然后就开始把T加入到V1中,因为V1中引入了T,因此V2中的点的到B的最短路径就应该进行刷新,因为之前在求这些点的到B的最短路径时,

没有考虑T的影响,这次将T加入以后,就要遍历与T连通,并且还在V2中的点,看是否通过T,这些点到B的最短路径还会更短,如果更短,则刷新这些点最短路径的长度(数组D的相应值)。

就这样反复运行上面的操作,直到所有的点都已经在V1中了(其实运行 点的个数 - 1 次 以后,就可以了,因为没一次必然求出一个点到B的最短路径)。

DJ算法的关键是,掌握了到B的所有通路,这样每次,这些通路中最短,并且终点是还没有确定最短路径的点E,的通路必然是E到B的最短路径L,因为首先L

要小于等于所有的其他通路LN,而DJ的前提又是所有的权值>=0, 因此保证了E从其他路径走 也必然会经过其他通路LN,而LN+非负数必然大于等于L,因此当前选择最短是最优的贪心解。

放到这道题里面,就是把上面的最短路径长度 变成了 最大的重量,选取下一个点的判断条件变一下,其他都一样.

证明:每次选取能使weight最大的点,这样就保证了,这一定是该点到起始点的最大weight。

假设当前V2已经有若干点(1,2,...N)确定了从自己当前到B的weight(但还不是最优的weight),从大到小排序为:L1>L2>...LN, 那么点1到B的最大weight必然就是L1,

反证: 如果有其他的路径能使从1到B的weight更大,那么这个路径必然会经过 2....N这些点,而根据题意,能经过2....N这些点到B,其最终的weight不可能大于L2...LN(因为一条路径的最终允许的weight是该路径中weight最小的那一段路径), 而又由L1>L2>...LN,因此不可能有更大的weight。因此,1到B的最大weight必然就是L1。

DJ的精髓其实就在上面,很多题的转化可以朝这个方向考虑.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值