Heavy Transportation
题目链接:专题四 最短路练习 - C - Heavy Transportation POJ - 1797
题意
给你n个点,m条边,并且每条边都有一个权值,定义Min1为一条路径中的最小边权值,求从点1开始到达点N最大的Min1
思路一 (二分+Djs)
既然是最大的最小边,那么用二分应该是没问题的,我看了一下数据,点小于等于1e3,数据量不大,我就简单二分套了个迪杰斯特拉
代码一
/*
Time : 1172
Mem : 4.7
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <ctime>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b) memset(a,b,sizeof(a))
#define sz(x) ((int)(x).size())
#define pb push_back
typedef long long ll;
const int INF = (int)0x3f3f3f3f;
const int MAXN = (int)1e3+7;
int N,M;
int S,E;
int G[MAXN][MAXN];
int dis[MAXN];
int vis[MAXN];
bool OK(int n){
mmm(dis,0x3f);
mmm(vis,0);
dis[S] = 0;
int mn,now;
rep(i,1,N){
mn = INF,now = 0;
rep(j,1,N){
if (!vis[j] && dis[j] < mn){
mn = dis[j];
now = j;
}
}
if (now == 0)break;
vis[now] = 1;
rep(j,1,N){
if (G[now][j] >= n && dis[j] > G[now][j]+dis[now]){
dis[j] = G[now][j]+dis[now];
}
}
}
if (dis[E] != INF) return 1;
else return 0;
}
void initAll(){
mmm(G,0x3f);
mmm(dis,0x3f);
mmm(vis,0);
}
int main()
{
int T;
scanf("%d",&T);
rep(ca,1,T) {
initAll();
scanf("%d %d",&N,&M);
rep(i,1,M){
int x,y,c;
scanf("%d %d %d",&x,&y,&c);
G[x][y] = G[y][x] = c;
}
S = 1,E = N;
int l = 0,r = 1e6+2;
while (l <= r){
int m = (l+r)>>1;
if (OK(m)) l = m+1;
else r = m-1;
}
printf("Scenario #%d:\n%d\n\n",ca,r);
}
}
/*
2
3 3
1 2 3
1 3 5
2 3 5
3 3
1 2 30
1 3 40
2 3 50
*/
思路二 (直接 Djs)
看了大神的时间,我发现我的时间消耗基本上是最多的了,原来别人没有使用二分,而是直接用了一个迪杰斯特拉,dis里面储存的不是最短路了,而是到这个点所需要的Min1。这样别人就只需要用一次迪杰斯特拉了。
代码二 (邻接表)
/*
Time : 391
Mem : 4.7
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <ctime>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b) memset(a,b,sizeof(a))
#define sz(x) ((int)(x).size())
#define pb push_back
typedef long long ll;
const int INF = (int)0x3f3f3f3f;
const int MAXN = (int)1e3+7;
int N,M;
int S,E;
int G[MAXN][MAXN];
int dis[MAXN];
int vis[MAXN];
int Djs(){
int mn,now;
rep(i,1,N){
dis[i] = G[1][i];
}//好吧预处理还是很重要的
rep(i,1,N){
mn = 0,now = 0;
rep(j,1,N){
if (!vis[j] && dis[j] > mn){
mn = dis[j];
now = j;
}
}
if (now == 0)break;
vis[now] = 1;
//从当前dis最大的点开始向周围松弛
rep(j,1,N){
if (dis[j] < min(G[now][j],dis[now])){ // 如果这个点的dis比G[now][j]和dis[now]的最小值还小就替换
dis[j] = min(G[now][j],dis[now]);
}
}
}
return dis[E];
}
void initAll(){
mmm(G,0);
mmm(vis,0);
}
int main()
{
int T;
scanf("%d",&T);
rep(ca,1,T) {
initAll();
scanf("%d %d",&N,&M);
rep(i,1,M){
int x,y,c;
scanf("%d %d %d",&x,&y,&c);
G[x][y] = G[y][x] = c;
}
S = 1,E = N;
printf("Scenario #%d:\n%d\n\n",ca,Djs());
}
}
/*
2
3 3
1 2 3
1 3 5
2 3 5
3 3
1 2 30
1 3 40
2 3 50
*/
代码三 (vector核心代码)
/*
Time : 329
Mem : 1.8
*/
struct Node{
int to,cost;
Node(int t=0,int c=0):to(t),cost(c){}
};
vector<Node> vp[MAXN];
queue<int> qu;
int Djs(){
while (!qu.empty())qu.pop();
qu.push(S);
while (!qu.empty()){
int k = qu.front();
qu.pop();
rep(i,0,sz(vp[k])-1){
int t = vp[k][i].to;
int c = vp[k][i].cost;
if (k == 1) dis[t] = c,qu.push(t); //这步很关键
else if (dis[t] < min(dis[k],c)){
dis[t] = min(dis[k],c);
qu.push(t);
}
}
}
return dis[E];
}
思路三 (最大生成树)
其实就是求最大生成树的最小边权,但是这里其实还有个小陷阱,就是所有的点不需要全部都连接,只要1和连接起来即可。
代码四 (Kruskal)
/*
Time : 282
Mem : 12.6
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <ctime>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b) memset(a,b,sizeof(a))
#define sz(x) ((int)(x).size())
#define pb push_back
typedef long long ll;
const int INF = (int)0x3f3f3f3f;
const int MAXN = (int)1e3+7;
int N,M;
struct Node{
int x,y,c;
Node(int x = 0,int y = 0,int c = 0):x(x),y(y),c(c){}
}G[MAXN*MAXN];
bool cmp(const Node& a,const Node& b){
return a.c > b.c;
}
int fa[MAXN];
int find1(int x){
if (x != fa[x])fa[x] = find1(fa[x]);
return fa[x];
}
bool Same(int x,int y){
return find1(x) == find1(y);
}
void Union(int x,int y){
int u = find1(x),v = find1(y);
if (u == v)return ;
fa[u] = v;
}
int Kruskal(){
int res = INF;
sort(G+1,G+1+M,cmp);
rep(i,1,M){
if (!Same(G[i].x,G[i].y)){
Union(G[i].x,G[i].y);
res = min(res,G[i].c);
}
if (Same(1,N))break;
}
return res;
}
void init(){
rep(i,0,N)fa[i] = i;
}
int main()
{
int T;
scanf("%d",&T);
rep(ca,1,T){
scanf("%d %d",&N,&M);
init();
rep(i,1,M){
scanf("%d %d %d",&G[i].x,&G[i].y,&G[i].c);
}
printf("Scenario #%d:\n%d\n\n",ca,Kruskal());
}
}
代码五 (Prim)
/*
Time : 360
Mem : 4.7
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <ctime>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b) memset(a,b,sizeof(a))
#define sz(x) ((int)(x).size())
#define pb push_back
typedef long long ll;
const int INF = (int)0x3f3f3f3f;
const int MAXN = (int)1e3+7;
int G[MAXN][MAXN];
int low[MAXN];
int vis[MAXN];
int N,M;
int Prim(){
int res = INF;
rep(i,1,N){
low[i] = G[1][i];
}
vis[1] = 1;
rep(i,1,N){
int mn = -INF,id = 0;
rep(j,1,N){
if (!vis[j] && mn < low[j]){
mn = low[j];
id = j;
}
}
res = min(res,mn);
vis[id] = 1;
if (id == N)break;
rep(j,1,N){
if (!vis[j] && low[j] < G[id][j]){
low[j] = G[id][j];
}
}
}
return res;
}
void init(){
mmm(G,-1);
mmm(vis,0);
mmm(low,-1);
}
int main()
{
int T;
scanf("%d",&T);
rep(ca,1,T){
scanf("%d %d",&N,&M);
init();
int x,y,w;
rep(i,1,M){
scanf("%d %d %d",&x,&y,&w);
G[x][y] = G[y][x] = w;
}
printf("Scenario #%d:\n%d\n\n",ca,Prim());
}
}