Fork me on GitHub

POJ1797-Heavy Transportation

继续刷邝斌飞最短路专题

垃圾POJ继续挂

可用平台

每次翻译都用这个,之前一段一段帖,今儿刚发现登陆可以无限制帖然后翻译

  

起初以为是从N点运输给各个街道输出最大重量,但样例输出4, 可是1到2那条路是3也不行啊,难道只需要运输到各个路口?但说每条路都要走啊

难到我图画错了?百度翻译说十字路口,难道题意是三字路口之类的?

翻译理解不明白真操蛋,找题解看翻译,还要尽量避免看到解题办法

找了个题解参考博客放大300%网页,只看题意部分说:“n个点,m条带权边,求点1到点n的所有路径中最小边的最大值”

稍微想了下这咋感觉好简单呢,都跟最短路不沾边

这不跟上面的题一模一样么,买一送一啊?

撸了一坨代码出来,TLE了

想想也是,n是10^3,3层for下来就10^9

 1 #include<stdio.h>
 2 #include<iostream>
 3 #include<string.h>
 4 #include<math.h>
 5 #include<iomanip>
 6 using namespace std;
 7 int weight[1001][1001];
 8 int minweight[1001][1001];//minweight[1][1000]表示第1岔路口到第1000岔路口的这条街道,能承载的最小重量.短板理论
 9 int main()
10 {
11 //    freopen("zhishu.txt","r",stdin);
12     int t;
13     cin>>t;
14     int p=t;
15     while(t--)
16     {
17         int n,m;
18         cin>>n>>m;
19         int a,b,c;
20         memset(minweight, 0x42,sizeof(minweight));
21         for(int i=0;i<m;i++){
22             cin>>a>>b>>c;
23             weight[a][b]=c;
24             weight[b][a]=c;
25             minweight[a][b]=c;
26             minweight[b][a]=c;
27         }
28 
29         for(int i=0;i<n;i++){
30             weight[i][i]=0;
31             minweight[i][i]=0;
32         }
33 
34         for(int k=0;k<n;k++){
35             for(int i=0;i<n;i++)
36                 for(int j=0;j<n;j++){
37                     if(minweight[i][j] < min(minweight[i][k],minweight[k][j])){
38                         minweight[i][j] = min(minweight[i][k],minweight[k][j]);//让每段的最大值最小,比如2+4和5,最大值分别为4和5,我要取2+4这条路
39                     }
40                 }
41         }
42         cout<<"Scenario #"<<p-t<<":"<<endl;
43         cout<<minweight[1][n]<<endl;
44         cout<<endl;
45     }
46 }

其实A的两道最短路的题后,觉得弗洛伊德算法有点懂了,但迪杰斯特拉一直只懂个算法正确性,能给不懂的人逼逼两句,但变种啥的不灵活,根本没法做题,也就是根本不算懂这个算法。上个题我就有点强迫症不甘心,但又实在不想看别人代码,md现在机会来了

依旧是上面题解说的,眼睛只看到这句“和poj2253一样,只不过那题n<=200,可以用floyd,而这题floyd会TLE,所以用dijkstra来做”

 

我又好开心,直接去想迪杰斯特拉算法了

人一我十人十我百

妈的又想不起来,这次不看之前的博客了,看了也忘,麻痹的直接硬想硬憋!!

昨天看山岸逢花大爆射6点才睡13:30才醒来图书馆,之前都4点睡,11:00醒。没进入学习状态之前还在骑车的时候7点睡14:00醒,15:00出门18:00到图书馆,学到23:50
View Code

 

怎么都不会写,感觉vis用不上啊(能确定最优解才会把这个点加入,后面改动的时候不动他),可是哪一步都确定不了最优解啊,如图
顶点1到②④⑤的承重347这仨数,哪个重量都无法确定是他们到达目的地6的短板啊,想构造的话哪个都可以为答案
感觉只能用弗洛伊德啊

想让3是答案,只需要②③和③⑥尽可能大,④⑥和⑤⑥尽可能小

想让4是答案,只需要④⑥尽可能大,②③和③⑥和⑤⑥尽可能小

想让7是答案,⑤⑥尽可能大,只需要②③和③⑥和④⑥尽可能小

那这样的话用弗洛伊德不是更好么?咋用迪杰斯特拉啊,艹!

迪杰斯特拉思想是n步后得到最优解,

第1步找最短距离,即对于某点来说的最优解,后面咋变动,该点都不会有更优的解了,然后更新跟他沾亲带故的点

第2步在更新后的点中,找最短距离,然后更新跟他沾亲带故的点

可这题每一步都没有最优值啊,贪心个JB

看来刷题的好处就是之前博客说过,控制变量将最关键的算法本质抽丝剥茧出来,这个题,我发现了妈逼的明显每次将局部最优解加进来并不是算法本质!

我觉得之前博客学迪杰斯特拉的时候,是因为入度不方便写所以才弄的每次找最短路,入度为0时加哪个点都行!

 

我就瞎JB划了,写啊写(假设mindir[a]是从顶点到a点所有路径中,承载能力最弱的那条路径的,承载能力,我给他简称路径承载短板)

发现点东西,但感觉又没发现啥

换张纸再划了划了

感觉好像有点意思了,起初没啥感觉,路径和点都很少,但后面adc比的时候,推出了个公式(图片中倒数第二行),我发现如果可以把这个公式扩散到整个比较过程,问题不就解决了吗

 

紧接着尝试扩散公式,那起手是347仨数比较,找最大的,然后开始按照一个思路去操作:(数据用的是图里的,比如c假设为1那些,d的假设为2)

首先把①加入

找最大,7也就是加入,现在不确定是否vis是否需要标记,我只是照猫画瓢,假设加入,实际这个点后面做不做更改再说,反正就是先给它拎出来

(mindir[5],c)中的最小值作为此时这条路径的短板,这个最小值能否接着用,直到最后抵达目的地,要看这个最小值跟mindir[4]和mindir[2]比咋样(这里只是为了方便表述,其实mindir[4]、mindir[2]都还没出现,应该说是dir[1][4]和dir[1][2]),如果被比如说mindir[4]干倒,那此时延伸(或者说想目的地推进)到这的时候,最牛的短板,也就是短板数据里,最能载重的一定是④这条路径,所以,我依旧是找最大,找(mindir[5],dir[5][6])的最小值、mindir[4]、mindir[2]中的最大,到这步解释清楚了,我直接写这步的总结

找最大,4也就是④加入

(mindir[4],d)中的最小值作为此时这条路径的短板,去跟mindir[2]和mindir[6]比,只是为了方便表述,但其实此时mindir[6]还没出现呢,应该说是mindir[5]和dir[5][6]中的最小值,如果d是2,c是1,那应该是②进,也就是说:(midir[4],dir[4][6])中的最小值、(mindir[5],dir[5][6])、mindir[2]这仨数中的最大值进来,到这步解释清楚了,我直接写这步的总结

找最大,3也就是②加入

(mindir[2],a)中的最小值,

(mindir[4],d)中的最小值

(mindir[5],c)中的最小值

更精准点说就是:

(mindir[2],dir[2][3])中的最小值

(mindir[4],dir[4][6])中的最小值

(mindir[5],dir[5][6])中的最小值

上面这仨找最大,作为此时的短板路径最能称重的,那反复至此执行上面操作,到⑥加入的时候,mindir[6]不就是答案了吗

至此感觉公式推出来了,再把这个公式套在上面7也就是⑤加入看行不行,那句 找(mindir[5],dir[5][6])、mindir[4]、mindir[2]中的最大 就变成了找

(mindir[5],dir[5][6])中的最小值、(mindir[1],dir[1][4])中的最小值、(mindir[1],dir[1][2])中的最小值

仨数中的最大,作为即将加入的点

这么列出来还有个好处是方便我去memset初始值,比如mindir[1]也要弄成最大(但开始写的时候发现不太对,边写边改吧)

 

以上是完全忘记迪杰斯特拉,才能想出来的,不然束手束脚根本想不出来,可是想出来发现,这怎么好像还是弗洛伊德呢?

 

不管了看看代码咋实现,边写边记录问题

1、dir其实有点歧义,名为为weight比较好

2、mindir一开始memset成最大

3、vis没啥用啊

4、实际写的时候发现好像可以不用像公式推导的那么麻烦

5、但为啥我之前看上一个题青蛙的那个,看题解迪杰斯特拉法用到了vis数组呢?整的我都不敢写了

第一次写提交WA

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<math.h>
 4 #include<iostream>
 5 using namespace std;
 6 int weight[1001][1001];//初始数据
 7 
 8 int minweight[1001];
 9 //发现之前弗洛伊德TLE代码里注释表述不当,最小值tm是0啊,重新表述下:minweight[1000]表示第1岔路口到第1000岔路口的这条街道,minweight[800]表示第1岔路口到第800岔路口的这条街道,经过的路径中,承载能力最小的那条路径的承载数值.短板理论,后面让这个数值最大即所求
10 int vis[1001];//vis[2]=1表示2这个点已经加入集合,意思就是这个点判断完了,是伪最优,之后再判断的时候,从2出发看,比如图里的我2和4的vis都是1,那下次就2和4出发去弄,5没加进来vis不是1是0,那我就还1到5判断
11 int thismax;
12 int main()
13 {
14     freopen("zhishu.txt","r",stdin);
15     int t;
16     cin>>t;
17     int tp=t;
18     while(t--)
19     {
20         memset(weight,0x3f,sizeof(weight));
21         int n,m;//n当作点,m当作边
22         cin>>n>>m;
23         memset(minweight,0x3f,sizeof(minweight));
24         memset(vis,0,sizeof(vis));
25 
26         int a,b,c;
27         for(int i=0;i<m;i++){
28             cin>>a>>b>>c;
29             weight[a][b]=c;
30             weight[b][a]=c;//数据输入完毕
31         }
32 
33         for(int i=1;i<=n;i++)
34             minweight[i]=weight[1][i];
35         minweight[1]=0;
36 
37         int p;
38         for(int i=1;i<=n;i++){
39             thismax=0;
40             for(int j=1;j<=n;j++){
41                 if(thismax<minweight[j]);
42                     p=j;
43             }
44 //            vis[p]=1;
45             for(int j=1;j<=n;j++){
46                 if(minweight[j]>min(minweight[p],weight[p][j]))
47                     minweight[j]=min(minweight[p],weight[p][j]);//非常难想
48             }
49         }
50 
51         cout<<"Scenario #"<<tp-t<<":"<<endl;
52         cout<<minweight[n]<<endl;
53         cout<<endl;
54     }
55 }

把我上面图里的数据测试下

1
6 7
1 2 3 
1 4 4
1 5 7
5 6 1
4 6 2
2 3 5
3 6 4

妈的初始值是0x3f3f3f3f,现在要找3、4、7有数的里面无穷大,结果不0x3f3f3f3f找进来了

我要比较的只是运算过的,也就是说别人别掺乎,比如在数值7,也就是⑤加进来后,该比较3、4、和c了,那我搞个vis

 

这个vis搞的我写了又重构,写了又重构,反复搞好久(这块的逻辑很重要,一定自己想出来,别看别人写的,我起初试了好几种方法写)

想过把1点vis赋1,所有跟1有路径的赋1,然后比较,找出最大值的那个点标记为p,然后vis[p]=0,意思是,p已经加进来了,那下次你就别跟着比了,为啥?因为比的话找最大,应该让没进来的那些但还能从1到达的,和我p点进来后的p下面那些路去比。比如第一次⑤进来了,下一次1到5就别比了,让1到2、1到4、5到6去比,你滴明白?然后我把所有p点能到的除了1,vis都赋成2,然后把判断最大值语句改成是1就比mindir,是2就比距离,但写不下去了,这距离应该是刚出去的那个p点也就是⑤作为起点,刚加进去的那些点作为终点,看两点之间的距离,但不行啊,没法有效调出我想要的这个p点,这个点以后也要用到,这么写没法整

 

麻痹的后来发现还是迪杰斯特拉算法里,直接放入集合下次判断不考虑他的写法是对的,不用特意判断两点距离,因为后面的松弛操作已经记录到mindir里了

一下子豁然开朗了

 

 

发现上面WA里的松弛那个比较写反了,命名也很容易误导,应该叫maxdir,但对上面讲的没影响

妈的导致memset也搞反了。然后比较大小那也没重新给thismax赋值,这里初始值真他妈不好想啊!!!

改完AC了

AC代码

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<math.h>
 4 #include<iostream>
 5 using namespace std;
 6 int weight[1001][1001];//初始数据
 7 
 8 int maxweight[1001];
 9 //发现之前弗洛伊德TLE代码里注释表述不当,最小值tm是0啊,重新表述下:maxweight[1000]表示第1岔路口到第1000岔路口的这条街道,maxweight[800]表示第1岔路口到第800岔路口的这条街道,经过的路径中,承载能力最小的那条路径的承载数值.短板理论,后面让这个数值最大即所求
10 int vis[1001];//vis[2]=1表示2这个点已经加入集合,意思就是这个点判断完了,是伪最优,之后再判断的时候,从2出发看,比如图里的我2和4的vis都是1,那下次就2和4出发去弄,5没加进来vis不是1是0,那我就还1到5判断
11 int thismax;
12 int main()
13 {
14 //    freopen("zhishu.txt","r",stdin);
15     int t;
16     cin>>t;
17     int tp=t;
18     while(t--)
19     {
20         memset(weight,0x3f,sizeof(weight));//没路是0,或者无穷大都行,0也可以AC
21         int n,m;//n当作点,m当作边
22         cin>>n>>m;
23         memset(maxweight,0,sizeof(maxweight));
24         memset(vis,0,sizeof(vis));
25 
26         int a,b,c;
27         for(int i=0;i<m;i++){
28             cin>>a>>b>>c;
29             weight[a][b]=c;
30             weight[b][a]=c;//数据输入完毕
31         }
32         for(int i=1;i<=n;i++)
33             weight[i][i]=0;
34 
35         for(int i=1;i<=n;i++)
36             if(weight[1][i]!=0x3f3f3f3f)
37                 maxweight[i]=weight[1][i];//1到自身都是0,其他有路都是具体数值
38         int p;
39         //vis[1]用不到
40         for(int i=1;i<=n;i++){
41             thismax=0;
42             for(int j=1;j<=n;j++){
43                 if(thismax<maxweight[j]&&vis[j]==0){
44                     p=j;
45                     thismax=maxweight[j];
46                 }
47             }
48             vis[p]=1;
49 //cout<<"!"<<p<<" "<<vis[p]<<" $"<<vis[2]<<endl;
50             for(int j=2;j<=n;j++){//松弛
51                 if(weight[p][j]!=0x3f3f3f3f)//确定是沾亲带故,否则这段没有路,min就是0x3f3f3f3f,那不考虑是不是沾亲带故,就把这个没路的给整成有路了,沾亲带故其实就是从这个点出发,有路可以走的.原算法是相加,无穷大依旧是无穷大,但这里是比较,会将没路的更新成某个数值
52                     if(maxweight[j]<min(maxweight[p],weight[p][j])){
53                         maxweight[j]=min(maxweight[p],weight[p][j]);
54                     }
55 //                    cout<<"#######"<<maxweight[j]<<endl;
56             }
57         }
58 
59         cout<<"Scenario #"<<tp-t<<":"<<endl;
60         cout<<maxweight[n]<<endl;
61         cout<<endl;
62     }
63 }

另一种AC写法(全0写法)

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<math.h>
 4 #include<iostream>
 5 using namespace std;
 6 int weight[1001][1001];
 7 int maxweight[1001];
 8 int vis[1001];
 9 int thismax;
10 int main()
11 {
12 //    freopen("zhishu.txt","r",stdin);
13     int t;
14     cin>>t;
15     int tp=t;
16     while(t--)
17     {
18 //        memset(weight,0x3f,sizeof(weight));//没路是0,或者无穷大都行
19         memset(weight,0,sizeof(weight));//没路是0,或者无穷大都行,上面那行也AC
20         int n,m;
21         cin>>n>>m;
22         memset(maxweight,0,sizeof(maxweight));
23         memset(vis,0,sizeof(vis));
24 
25         int a,b,c;
26         for(int i=0;i<m;i++){
27             cin>>a>>b>>c;
28             weight[a][b]=c;
29             weight[b][a]=c;//数据输入完毕
30         }
31         for(int i=1;i<=n;i++)
32             weight[i][i]=0;
33 
34         for(int i=1;i<=n;i++)
35 //            if(weight[1][i]!=0x3f3f3f3f)
36                 maxweight[i]=weight[1][i];//1到自身都是0,其他有路都是具体数值
37         int p;
38         for(int i=1;i<=n;i++){
39             thismax=0;
40             for(int j=1;j<=n;j++){
41                 if(thismax<maxweight[j]&&vis[j]==0){
42                     p=j;
43                     thismax=maxweight[j];
44                 }
45             }
46             vis[p]=1;
47             for(int j=2;j<=n;j++){//松弛
48 //                if(weight[p][j]!=0x3f3f3f3f)//确定是沾亲带故,否则这段没有路,min就是0x3f3f3f3f,那不考虑是不是沾亲带故,就把这个没路的给整成有路了,沾亲带故其实就是从这个点出发,有路可以走的.原算法是相加,无穷大依旧是无穷大,但这里是比较,会将没路的更新成某个数值
49                     if(maxweight[j]<min(maxweight[p],weight[p][j])){
50                         maxweight[j]=min(maxweight[p],weight[p][j]);
51                     }
52             }
53         }
54         cout<<"Scenario #"<<tp-t<<":"<<endl;
55         cout<<maxweight[n]<<endl;
56         cout<<endl;
57     }
58 }

又另一种AC写法

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<math.h>
 4 #include<iostream>
 5 using namespace std;
 6 int weight[1001][1001];
 7 int maxweight[1001];
 8 int vis[1001];
 9 int thismax;
10 int main()
11 {
12 //    freopen("zhishu.txt","r",stdin);
13     int t;
14     cin>>t;
15     int tp=t;
16     while(t--)
17     {
18 //        memset(weight,0x3f,sizeof(weight));//没路是0,或者无穷大都行
19         memset(weight,0,sizeof(weight));//没路是0,或者无穷大都行,上面那行也AC
20         int n,m;
21         cin>>n>>m;
22         memset(maxweight,0,sizeof(maxweight));
23         memset(vis,0,sizeof(vis));
24 
25         int a,b,c;
26         for(int i=0;i<m;i++){
27             cin>>a>>b>>c;
28             weight[a][b]=c;
29             weight[b][a]=c;//数据输入完毕
30         }
31         for(int i=1;i<=n;i++)
32             weight[i][i]=0;
33 weight[1][1]=0x3f3f3f3f;
34         for(int i=1;i<=n;i++)
35 //            if(weight[1][i]!=0x3f3f3f3f)
36                 maxweight[i]=weight[1][i];//1到自身是0,其他有路都是具体数值,没路是无穷大
37         int p;
38         for(int i=1;i<=n;i++){
39             thismax=0;
40             for(int j=1;j<=n;j++){
41                 if(thismax<maxweight[j]&&vis[j]==0){
42                     p=j;
43                     thismax=maxweight[j];
44                 }
45             }
46             vis[p]=1;
47             for(int j=1;j<=n;j++){//松弛
48 //                if(weight[p][j]!=0x3f3f3f3f)//确定是沾亲带故,否则这段没有路,min就是0x3f3f3f3f,那不考虑是不是沾亲带故,就把这个没路的给整成有路了,沾亲带故其实就是从这个点出发,有路可以走的.原算法是相加,无穷大依旧是无穷大,但这里是比较,会将没路的更新成某个数值
49                     if(maxweight[j]<min(maxweight[p],weight[p][j])){//没有路就是0,min函数中比较,对于没路的点,一定是0胜出,0不可能大于任何数,所以这一步相当于间接筛掉了那些不是沾亲带故的
50                         maxweight[j]=min(maxweight[p],weight[p][j]);
51                     }
52             }
53         }
54         cout<<"Scenario #"<<tp-t<<":"<<endl;
55         cout<<maxweight[n]<<endl;
56         cout<<endl;
57     }
58 }

说下思路(win+←开俩标签也看,对比上面那个图)

首先找①点到能到达的里面最大的,是7,找出后,⑤点选出来了,做跟他沾亲带故的松弛,松弛完该干啥了?

显然是比较①②、①④、⑤⑥仨数(3、4、1)谁大啊,更确切的来说,不是⑤⑥而是刚加进来的⑤点沾亲带故更新后①⑤和⑤⑥之间的短板称重

发现①④最大,但这个最大代码怎么写,理论上来说是要有⑤⑥承重数据参与的,因为他是①⑤和⑤⑥的min嘛,但问题来了,循环内你咋去找这个起点⑤,如果很多步之后有很多个这种非①点作为起始的两点称重数据段参与比较,起点你咋找?于是我发现其实在松弛的时候这个⑤⑥称重就已经当作短板记录到了minweight[6]当中,即minweight[6]是1,那我是不是直接for遍历整个点就行了?即①到②③④⑤⑥最大,但注意①到⑤还用掺乎进来比了吗,显然他再大都已经没用了,已经有了⑤⑥作为短板承重了,到这豁然开朗,设置个vis,⑤进来过就赋值为1,下次别进来跟着比了,目前也就更加了解迪杰斯特拉算法本质,每次找的局部最优,在原始算法中亦是全局最优,也就是说,到某点的,此时的,最短距离,那该点加进来后,一直到最后也是顶点到该点最短的,但此题又发现,每次加进来的比如第一次⑤加进来,但最后①⑥短板承重答案是3,即①②③⑥,跟⑤没关系,⑤只是伪最优,是向真最优答案方向发展了,无数个伪最优中,到尽头,一定是真最优,叙述到这,一些词汇跟我最开始博客里的一些话就对上了,所以没有这个推导过程,直接看我这个总结结论就是一堆天数屁话根本看不懂,所以还得自己亲自推导啊。然后,虽然说⑤加进来之后不再加进来了,且⑤走完就到⑥了,但没关系,后面其他点进入会使得⑤或者⑥更能承重,则松弛

再说代码里的想了我好久的memset问题,我想到了三种写法:(代码里的注释可能是乱的,看下面的就行)

“另一种AC写法(全0写法)”

maxweight:①到某点的承重赋上初始给定的值,其他memset为0

至于weight,一开始memset全0,俩俩之间有路径的的赋值为具体距路径承重

然后重点来了,比较的时候,两点之间没有路,即不是刚刚加入的沾亲带故的点(加入的点用p标记了),就是0,min函数中比较,对于没路的点, min(maxweight[p],weight[p][j]) 这句话一定返回的是weight[p][j]的值,也就是没路的,也就是0,0不可能大于任何数,所以这一步相当于间接筛掉了那些不是沾亲带故的

如果是遍历的加入的点,也即是自身的话,⑤加进来,7<min(7,0)不成立,不会松弛,至此结束

再来说说最开始那个“AC代码”

maxweight,①到该点有路就赋具体值,1到1是0,没路也是0

weight,有路的赋具体数值,自身到自身是0,没路是0x3f3f3f3f无穷大

然后重点来了,比较的时候要加上一句 if(weight[p][j]!=0x3f3f3f3f) ,没路的就别松弛了,会出错,比如我下面这个图

如果轮到④加进去,假设使得maxweight[5]是3,遍历如果遍历到没路的⑦这个点,比较后就就会进行松弛。我起初以为小数2不可能在大数3之前加进去,后来明白了这是遍历不是找最大那个操作

注意:上面两个代码都是从2开始松弛的,试想一下,如果是从1开始,1到1是0,松弛的时候,如果⑤加进来,松弛到1,0 < min(7,7)成立,就会把1到自身给错误地松弛掉。这也就有了

“又另一种AC写法”

将1到1的承重初试设为无限大就没事了,即 weight[1][1]=0x3f3f3f3f; 

但我写到这突然又发现个事,如果maxweight[1]设无限大,第一次进入的就是1点,那我松弛的时候,就可以进行类似于起初初始化赋值操作,所以起初赋值那也省了。更新最简洁代码

 

 

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<math.h>
 4 #include<iostream>
 5 using namespace std;
 6 int weight[1001][1001];
 7 int maxweight[1001];
 8 int vis[1001];
 9 int thismax;
10 int main()
11 {
12 //    freopen("zhishu.txt","r",stdin);
13     int t;
14     cin>>t;
15     int tp=t;
16     while(t--)
17     {
18         memset(weight,0,sizeof(weight));
19         int n,m;
20         cin>>n>>m;
21         memset(maxweight,0,sizeof(maxweight));
22         memset(vis,0,sizeof(vis));
23 
24         int a,b,c;
25         for(int i=0;i<m;i++){
26             cin>>a>>b>>c;
27             weight[a][b]=c;
28             weight[b][a]=c;//数据输入完毕
29         }
30         for(int i=1;i<=n;i++)
31             weight[i][i]=0;
32         maxweight[1]=0x3f3f3f3f;
33 //        for(int i=1;i<=n;i++)
34 //            maxweight[i]=weight[1][i];
35         int p;
36         for(int i=1;i<=n;i++){
37             thismax=0;
38             for(int j=1;j<=n;j++){//找最大
39                 if(thismax<maxweight[j]&&vis[j]==0){
40                     p=j;
41                     thismax=maxweight[j];
42                 }
43             }
44             vis[p]=1;
45             for(int j=1;j<=n;j++){//松弛
46                 if(maxweight[j]<min(maxweight[p],weight[p][j])){
47                     maxweight[j]=min(maxweight[p],weight[p][j]);
48 
49                 }
50             }
51         }
52         cout<<"Scenario #"<<tp-t<<":"<<endl;
53         cout<<maxweight[n]<<endl;
54         cout<<endl;
55     }
56 }

 

艹!兜兜转转发现就是之前最原始的算法的写法,但只有这样自己趟过一遍才能更了解算法思想

至此OK

看看别人代码咋写的

 

大部分用了队列,妈的我发现我代码是最朴素的,就跟原始人似得,其他人都用了点高科技,比如pair,map啥的,等刷完邝斌飞开始学C++再弄那些吧

有说最大生成树的(邝斌有这个专题,不管了,后面再说),随手放俩感觉还不错的博客参考博客

他们博客里写的都更专业,但不接地气,不知道思路的根本看不懂,什么状态转移方程,队列取最大,我只能一个一个核对最后发现是一样的,但对不知道咋解题的很不友好,没有桥梁衔接

 

更新:刷后面Wormholes的时候,发现POJ好了,把之前的代码交下发现,cin会超时,改后POJ也能AC的代码如下

AC代码

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<math.h>
 4 #include<iostream>
 5 using namespace std;
 6 int weight[1001][1001];//初始数据
 7 
 8 int maxweight[1001];
 9 //发现之前弗洛伊德TLE代码里注释表述不当,最小值tm是0啊,重新表述下:maxweight[1000]表示第1岔路口到第1000岔路口的这条街道,maxweight[800]表示第1岔路口到第800岔路口的这条街道,经过的路径中,承载能力最小的那条路径的承载数值.短板理论,后面让这个数值最大即所求
10 int vis[1001];//vis[2]=1表示2这个点已经加入集合,意思就是这个点判断完了,是伪最优,之后再判断的时候,从2出发看,比如图里的我2和4的vis都是1,那下次就2和4出发去弄,5没加进来vis不是1是0,那我就还1到5判断
11 int thismax;
12 int main()
13 {
14 //    freopen("zhishu.txt","r",stdin);
15     int t;
16     scanf("%d",&t);
17     int tp=t;
18     while(t--)
19     {
20         memset(weight,0x3f,sizeof(weight));//没路是0,或者无穷大都行,0也可以AC
21         int n,m;//n当作点,m当作边
22         scanf("%d%d",&n,&m);
23         memset(maxweight,0,sizeof(maxweight));
24         memset(vis,0,sizeof(vis));
25 
26         int a,b,c;
27         for(int i=0;i<m;i++){
28             scanf("%d%d%d",&a,&b,&c);
29             weight[a][b]=c;
30             weight[b][a]=c;//数据输入完毕
31         }
32         for(int i=1;i<=n;i++)
33             weight[i][i]=0;
34 
35         for(int i=1;i<=n;i++)
36             if(weight[1][i]!=0x3f3f3f3f)
37                 maxweight[i]=weight[1][i];//1到自身都是0,其他有路都是具体数值
38         int p;
39         //vis[1]用不到
40         for(int i=1;i<=n;i++){
41             thismax=0;
42             for(int j=1;j<=n;j++){
43                 if(thismax<maxweight[j]&&vis[j]==0){
44                     p=j;
45                     thismax=maxweight[j];
46                 }
47             }
48             vis[p]=1;
49 //cout<<"!"<<p<<" "<<vis[p]<<" $"<<vis[2]<<endl;
50             for(int j=2;j<=n;j++){//松弛
51                 if(weight[p][j]!=0x3f3f3f3f)//确定是沾亲带故,否则这段没有路,min就是0x3f3f3f3f,那不考虑是不是沾亲带故,就把这个没路的给整成有路了,沾亲带故其实就是从这个点出发,有路可以走的.原算法是相加,无穷大依旧是无穷大,但这里是比较,会将没路的更新成某个数值
52                     if(maxweight[j]<min(maxweight[p],weight[p][j])){
53                         maxweight[j]=min(maxweight[p],weight[p][j]);
54                     }
55 //                    cout<<"#######"<<maxweight[j]<<endl;
56             }
57         }
58 
59         cout<<"Scenario #"<<tp-t<<":"<<endl;
60         cout<<maxweight[n]<<endl;
61         cout<<endl;
62     }
63 }

 

 

 

###:总结下弗洛伊德算法就是,加点,然后大遍历,点咋加都行但必须每个点都加一遍,大遍历的时候也是咋遍历都行,但必须全部遍历到

###:题意其实就是有个巨轮推土机,要从1去往n,基于根据短板理论,找最牛逼的最能承重的路径

###:代码有思路不知道咋写最好的办法就是硬憋

学习新算法不知道怎么实现,最好的办法就是可以先看一遍代码,然后记住算法原理,忘记看的代码,硬憋,一点都不要有之前代码的痕迹记忆。如果你有思路但写不出来代码,这时候照着代码抄一遍,基本就完犊子了,脑瓜子里存了一堆挥之不去的脏数据。那些代码博客是自己A了好多题后水平高了才能看懂了

如果知道啥算法没思路,也硬憋,看题解基本一点用处没有,请教过山理首金金泽巨说把握看题解的时间,想1h,但我是想超过2天才看题解,毕竟我思路慢,但这样逐渐就会像惊蛰雨一样,1h就可以看题解了。主要是要做到1h内把所有可能都想到都没其他办法了才行。不然永远是看题解然后心中:“确实,是这么回事”,但毫无长进,到区域赛赛场上只能说足无措的坐在那看别人挂气球,读题翻译想思路+写代码+找bug,就成了读题翻译写代码找bug都一个人,你在那擦键盘喂面包端茶倒水。美赛3天(英语专业写论文+做实验数据+翻译,你在那呆呆的无所事事)

###恍惚之间总用弗洛伊德的思想去想迪杰斯特拉

###:我是顺序思路进行写的博客,很多人想完直接写结论,导致根本看不懂,有时候别人的博客要倒着看

###:今W钰H兄弟主动找我,害十一来玩的时候就想给他买点坚果,但没工作进度又慢的要死,没脸见,还是找到工作再联系他吧

###:一星期后回来看自己博客,发现都不愿意看

posted @ 2024-10-10 22:53  GerJCS  阅读(3)  评论(0编辑  收藏  举报