//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的精髓其实就在上面,很多题的转化可以朝这个方向考虑.