有关毒瘤 · 洛谷 · 玛丽卡
一、题目描述
话说麦克找新女朋友管我P事
二、输入输出
输出一个最长的时间,我们还可以了解玛丽卡走的是当前条件下的最短路径
输入 :题面可知麦克在1号点,玛丽卡在n号点
三、最基础的分析
-----------------------------------------下面我将用画图来为大家解读-----------------------------------------
样例的图如下:
我们根据题意已知麦克在1号点,玛丽卡在n号点,并且图为无向图。
显然:当前的最短路径为5 => 2 => 1 时间总和为1 + 8 = 9
当然,那么当5 => 2堵车了,怎么办呢?
也就是说5 => 2这条边不存在了,这时候的图转变为:
显然:当前的最短路径有两条:
分别是:5 => 3 => 4 => 1 和 5 => 3 => 2 => 1。
时间总和分别为:10 + 7 + 10 = 27 和 10 + 9 + 8 = 27
是不是看到这里觉得就可以停止了呢,其实不然,到此为止只切割了首次最短路径的其中一条边,事实上需要将每一条边都切割掉再进行寻找最短路径。
于是又会出现一种图:
显然:此时的最短路径也有两条:
分别是:5 => 2 => 4 => 1 和 5 => 3 => 4 => 1。
时间总和分别为:1 + 10 + 10 = 21 和 10 + 7 + 10 = 27
到此为止,该情况才结束。
综合上述分析:
第一步操作:找到完整图并且找到最短路记录时间与max = 0比较,并记录每一条边的编号
第二步操作:将记录下的边依次删去后再次寻找最短路并记录时间取最大值
最后一步操作:输出最大的时间
四、算法实现
SPFA算法:
代码实现:
#include<cstdio>
#include<queue>
#include<cstring>
#include<vector>
const int maxn = 1001;
const int maxm = 499501;
const int inf = 0x3f3f3f3f;
using namespace std;
struct edge{
int next;
int to;
int w;
}e[4995010];
int head[maxn];
int ecnt;
int n,m;
void Init(){ //初始化
for(int i = 0 ; i < maxm ; i++) e[i].next = 0;
for(int i = 0 ; i < maxn ; i++) head[i] = 0;
ecnt = 0;
}
void addedge(int u,int v,int w){
e[++ecnt] = (edge){head[u],v,w};
head[u] = ecnt;
}
void Insert(int x){
for(int i = 1 ; i <= x ; i ++){
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
}
int dis[maxn],cnt1[maxn],cnt2[maxn];
int CUT[1005][1005],f[1001];
int Ans = 0;
int flag;
bool vis[maxn];
void SPFA(){
queue<int> Q;
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[1] = 0;
vis[1] = true;
Q.push(1);
while(!Q.empty()){
int x = Q.front();Q.pop(); //立即弹出
vis[x] = false;
for(int i = head[x] ; i ; i = e[i].next){
if(CUT[x][e[i].to] == 0 && dis[e[i].to] > dis[x] + e[i].w){
if(!flag)f[e[i].to] = x;
int y = e[i].to , z = e[i].w;
dis[y] = dis[x] + z;
if(!vis[e[i].to]){
vis[e[i].to] = true;
Q.push(e[i].to);
}
}
}
}
return;
}
int main(){
scanf("%d %d",&n,&m);
Insert(m);
SPFA();
flag = 1;
for(int i = n ; i != 1 ; i = f[i]){
CUT[f[i]][i] = 1;
CUT[i][f[i]] = 1;
SPFA();
CUT[f[i]][i] = 0;
CUT[i][f[i]] = 0;
Ans = Ans > dis[n] ? Ans:dis[n];
}
printf("%d",Ans);
return 0;
}
迪杰克斯拉算法:
代码实现:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<queue>
#include<assert.h>
#include<ctime>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
#define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 1e3 + 5;
In ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
In void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
int n, m, c[maxn][maxn];
#define pr pair<int, int>
#define mp make_pair
int dis[maxn], pre[maxn];
bool vis[maxn];
priority_queue<pr, vector<pr>, greater<pr> > q;
In void dijkstra(int s, bool flg)
{
for(int i = 1; i <= n; ++i) dis[i] = INF, vis[i] = 0;
dis[s] = 0;
q.push(mp(0, s));
while(!q.empty())
{
int now = q.top().second; q.pop();
if(vis[now]) continue;
vis[now] = 1;
for(int i = 1; i <= n; ++i)
if(c[now][i])
{
if(dis[i] > dis[now] + c[now][i])
{
if(flg) pre[i] = now;
dis[i] = dis[now] + c[now][i];
q.push(mp(dis[i], i));
}
}
}
}
int main()
{
// MYFILE();
n = read(), m = read();
for(int i = 1; i <= m; ++i)
{
int x = read(), y = read(), w = read();
c[x][y] = c[y][x] = w;
}
dijkstra(1, 1);
int ans = 0;
for(int i = n; i > 1; i = pre[i])
{
int tp = c[i][pre[i]];
c[i][pre[i]] = c[pre[i]][i] = 0;
dijkstra(1, 0);
ans = max(ans, dis[n]);
c[i][pre[i]] = c[pre[i]][i] = tp;
}
write(ans), enter;
return 0; //此代码引用MRCLR学长
}
最后:
有关毒瘤数据开启O2优化可能会过,问题正在解决中……