poj1797 Heavy Transportation
来源:互联网 发布:netbeans运行java项目 编辑:程序博客网 时间:2024/05/22 06:27
链接:http://poj.org/problem?id=1797
题意:Hugo要把一些货物通过一个公路网络从点1运送到点n,每条公路有其自身的最大载重力wgt,公路是双向的。
求从点1到点n的所有公路中的最小载重量的最大值。即从点1到点n存在多条路径,对于每条路径又有一个最小的载重力。要求所有载重力中最大的那条路径,并输出。
这个题第一次做的时候没做出来,后来放了好久,今天又拿出来做,终于彻彻底底搞明白了。
最早就以为是用最小生成树的算法变形一下,生成最大树(必有n-1条边),然后再求这棵树中的最小的那条边。也就是说整个过程要生成n-1条边,才可以结束整个过程。
而这是错误的。
例如:
4 4
1 4 2
1 3 1
4 2 1
3 2 1
这个例子如果用上面的思想求,必然是1,而正确结果是2.
关键是题目要求只求从点1到n的一条路径即可,也就是说,即便还没达到n-1条边,只要到了这个点n,或者换句话说,点1和点n连通的时候,即可返回当前路径中最小的边。
清楚了这一点就好办了。
因为要求最小路径中的最大边,所以每一次选择边是选取最大的,这一点应该容易理解。所以,就可以用最短路或最小生成树的思想将其变形来做。
因为之前一直没搞清楚题意,写了prim提交,自己觉得明明正确啊!然后提交N次WA。。。哎。。然后就。。。
然后我就一口气写了三个版本的,其实可以算两个,一个是prim和kruskal,另一个是dijkstra,都只要变形一下就可以了。
/*Accept*//*Dijkstra*/#include<iostream>#include<cstring>#define MAXN 1010#define INF 1000005#define max(a,b) a>b?a:busing namespace std;int n,m;int map[MAXN][MAXN];int dist[MAXN];void dij(){int s[MAXN],mindis=INF;//数组s用于判断点是否被加入到路径中 //mindis用于存储当前路径中的最小边int i,j;for(i=1;i<=n;i++){ dist[i]=map[1][i]; //初始化dist[i] s[i]=0; //最初没有点加入数组s} dist[1]=0; s[1]=1; //起始点加入sfor(i=2;i<=n;i++){ int temp=0; int u=1; for(j=1;j<=n;j++) if(!s[j]&&dist[j]>temp) //s[j]必须没有访问过,路径始终选择最大的,与求最短路相反 { temp=dist[j];u=j; } s[u]=1; //将点u加入数组s if(temp<mindis) //更新mindis mindis=temp; if(u==n) //如果点1和点n连通时,则可直接输出mindis,然后跳出结束 { cout<<mindis<<endl; return; } for(j=1;j<=n;j++) if(!s[j]&&map[u][j]>0)//s[j]未访问且u、j连通 { int maxdis=max(dist[j],map[u][j]);//则取较大的那条边 dist[j]=maxdis; }}}int main(){int t,i,j,k,maxn;int a,b,c;cin>>t;for(k=1;k<=t;k++){ cin>>n>>m; if(n==1) //n=1的情况是我自己加的,其实不加也能过 //但加了输出的结果更符合实际些,个人觉得 { maxn=0; for(i=0;i<m;i++) { cin>>a>>b>>c; if(maxn<c) maxn=c; } cout<<"Scenario #"<<k<<":"<<endl; cout<<maxn<<endl; cout<<endl; continue; } for(i=1;i<=n;i++) for(j=1;j<=n;j++) map[i][j]=-1;//因为每次选取最大边,所以初值赋为1 for(i=0;i<m;i++) { cin>>a>>b>>c; map[a][b]=map[b][a]=c; } cout<<"Scenario #"<<k<<":"<<endl; dij(); cout<<endl;} return 0;}
/*Accept*//*Prim*/#include<iostream>#include<cstring>#define MAX 1005#define INF 1000005using namespace std;int trans[MAX][MAX];int lowcost[MAX],closest[MAX];int n,m;int maxPrim(int v){ int i,j,maxdis,mindis,minone; for(i=1;i<=n;i++) { lowcost[i]=trans[v][i]; closest[i]=v; } lowcost[v]=INF; mindis=INF; for(i=0;i<n-1;i++) { maxdis=0; for(j=1;j<=n;j++) if(lowcost[j]>0&&maxdis<lowcost[j]&&lowcost[j]!=INF)//与最小树相反,每次取最大 //lowcost[j]=-1,说明点j和点v(起始点)是不通的 //lowcost[j]=INF,说明点j已经在生成树中了 { maxdis=lowcost[j]; minone=j; } if(mindis>maxdis) {mindis=maxdis; } if(minone==n) //当点1和点n连通时,即可输出mindis,并结束程序 return mindis;lowcost[minone]=INF;for(j=1;j<=n;j++)if(trans[j][minone]>lowcost[j]) //和上面一样也是取最大{ lowcost[j]=trans[j][minone]; closest[j]=minone;} } return mindis;} int main(){int t,i,j,k,maxn;int a,b,c;cin>>t;for(k=1;k<=t;k++){ cin>>n>>m; if(n==1) { maxn=0; for(i=0;i<m;i++) { cin>>a>>b>>c; if(maxn<c) maxn=c; } cout<<"Scenario #"<<k<<":"<<endl; cout<<maxn<<endl; cout<<endl; continue; } for(i=1;i<=n;i++) for(j=1;j<=n;j++) trans[i][j]=-1;//赋初值为-1,因为是求最大生成树 for(i=0;i<m;i++) { cin>>a>>b>>c; trans[a][b]=c; trans[b][a]=c; } maxn=maxPrim(1); cout<<"Scenario #"<<k<<":"<<endl; cout<<maxn<<endl; cout<<endl;} return 0;}
/* Accept *//*Kruskal*/#include<iostream>#include<cstring>#include<algorithm>#define MAX 100005#define MAXN 1010#define INF 1000005using namespace std;int n,m;struct Edge //边的结构体{ int sta,end,wgt;}edge[MAX];int cmp(Edge a,Edge b){ return a.wgt>b.wgt;}int seeks(int *set,int v)//并查集应用{ int i; i=v; while(set[i]>0) i=set[i]; return i;}void kruskal(){ int set[MAXN],v1,v2,i,j; int mindis=INF; for(i=1;i<=n;i++) //set[i]初始化为0,但我一般见到最多的貌似是set[i]=i; //如果是set[i]=i,那么,上面查找的函数应该是这样的了 //while(set[i]!=i)i=set[i]; //当然这样也是可以的,我一直套用的是这个模板。set[i]=0; i=1; j=0; while(i<=n-1&&j<m) //i指当前生成树的边数,生成树要找n-1条边,j是边数 { v1=seeks(set,edge[j].sta); v2=seeks(set,edge[j].end);if(v1!=v2) //v1和v2不在同一个集合中{ set[v1]=v2; if(mindis>edge[j].wgt) //mindis的含义就不在赘述了 mindis=edge[j].wgt; if(seeks(set,1)==seeks(set,n)) //如果相等,则说明点1和点n已经连通 //一开始我把这个判断条件写错了,WA了N次。 { cout<<mindis<<endl; return ; } i++; //如果满足条件,则生成树的边要加1}j++; //j每次循环都要加1 } return ;}int main(){int t,i,k,maxn;int a,b,c;cin>>t;for(k=1;k<=t;k++){ cin>>n>>m; if(n==1) { maxn=0; for(i=0;i<m;i++) { cin>>a>>b>>c; if(maxn<c) maxn=c; } cout<<"Scenario #"<<k<<":"<<endl; cout<<maxn<<endl; cout<<endl; continue; } for(i=0;i<m;i++) { cin>>edge[i].sta>>edge[i].end; cin>>edge[i].wgt; } sort(edge,edge+m,cmp); cout<<"Scenario #"<<k<<":"<<endl; kruskal(); cout<<endl;} return 0;}
0 0
- Heavy Transportation (POJ1797)
- poj1797 - Heavy Transportation
- POJ1797--Heavy Transportation
- poj1797 Heavy Transportation
- POJ1797 Heavy Transportation 【Dijkstra】
- POJ1797 Heavy Transportation
- POJ1797 Heavy Transportation
- poj1797 Heavy Transportation
- [poj1797] Heavy Transportation
- POJ1797 Heavy Transportation
- POJ1797 Heavy Transportation
- POJ1797 Heavy Transportation
- POJ1797——Heavy Transportation
- 【POJ1797】Heavy Transportation 最短路
- poj1797 Heavy Transportation spfa变形
- 【POJ1797】Heavy Transportation【dijkstra优化】
- 【POJ1797】【Heavy Transportation】【dij变形】
- POJ1797 Heavy Transportation 最短路
- 常用的<注册表>运行命令
- Android中使用Animation实现控件的动画效果以及Interpolator和AnimationListener的使用
- linux--查看系统版本
- sprintf用法——把结果打印到打印字符串而不是终端
- iOS内购实现及测试排查错误列表
- poj1797 Heavy Transportation
- 点击按钮,表格自动增加一行的html代码
- Android ListView最佳处理方式,ListView拖动防重复数据显示,单击响应子控件
- android之Activity.startManagingCursor方法详解
- linux printk()的实现
- S5pv210 HDMI 接口在 Linux 3.0.8 驱动框架解析 (By liukun321 咕唧咕唧)
- orcl数据库的导入 导出
- [C#]上机实验:类的使用
- Android之Handler用法总结