题目链接:玛丽卡
第一时间想到的就是枚举每一条边使其堵塞, 然后跑SPFA, 求一个最大值。这样肯定不行(╮(╯▽╰)╭), 再想一下, 既然是影响最终的最短路, 那就应该在最短路上做手脚: 先跑一遍 SPFA,求出最短路径, 然后枚举最短路上的每一条边使其堵塞, 再跑SPFA, 求最大值。 这就减少了大量不必要的计算, 降低了复杂度(我第一次写的只有70分- -! 写太丑)。
还有要说的就是: 一定要细心再细心。。。。。。
/*
* Copyright © Eliot
* Date: 2016-10-26
* Author: Eliot
* QQ: 1161142536
* Description: 70分 玛丽卡
*/
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
#define MAX 1001
int N = 0, M = 0;
int x = 0, y = 0, c = 0;
/***********************
Description: 邻接表
***********************/
struct STRUCT {
int nPre;
int nTo;
int nVal;
}EDGE[100 * MAX];
int head[MAX] = { 0 };
int nCount = 0;
/***********************
Description: 添边
***********************/
void Add(int a, int b, int c) {
EDGE[++nCount].nTo = b;
EDGE[nCount].nVal = c;
EDGE[nCount].nPre = head[a];
head[a] = nCount;
}
/***********************
Description: SPFA最短路
***********************/
queue<int> Q;
int dis[MAX] = { 0 };
bool IsStack[MAX] = { false };
int SPFA(int nStart) {
memset(dis, 0x7, sizeof(dis));
Q.push(nStart);
IsStack[nStart] = true;
dis[nStart] = 0;
while (!Q.empty()) {
int nPoint = Q.front();
Q.pop();
IsStack[nPoint] = false;
for (int i = head[nPoint]; i != 0; i = EDGE[i].nPre) {
int nNextPoint = EDGE[i].nTo;
if (dis[nPoint] + EDGE[i].nVal < dis[nNextPoint]) {
dis[nNextPoint] = dis[nPoint] + EDGE[i].nVal;
if (!IsStack[nNextPoint]) {
IsStack[nNextPoint] = true;
Q.push(nNextPoint);
}
}
}
}
}
/***********************
Description: DFS求路径
***********************/
bool Is[MAX] = { false };
int Arr[MAX] = { 0 }, _A[MAX] = { 0 };
void DFS(int nPoint, int nLen, int Count, int nMin) {
for (int i = head[nPoint]; i != 0; i = EDGE[i].nPre) {
int nNextPoint = EDGE[i].nTo;
if (Is[nNextPoint]) continue;
Arr[Count] = nNextPoint;
Is[nNextPoint] = true;
nLen += EDGE[i].nVal;
if (nLen >= nMin) {
Arr[Count] = 0;
Is[nNextPoint] = false;
nLen -= EDGE[i].nVal;
continue;
}
if (nNextPoint == N && nMin == nLen) {
for (int i = 1; i <= Count; i++) _A[i] = Arr[i];
return;
}
else {
DFS(nNextPoint, nLen, Count + 1, nMin);
}
Is[nNextPoint] = false;
nLen -= EDGE[i].nVal;
}
}
/***********************
Description: 修改边权值
***********************/
int Change(int A, int B) {
int nRetn = 0;
for (int i = head[A]; i != 0; i = EDGE[i].nPre) {
if (EDGE[i].nTo == B) {
nRetn = EDGE[i].nVal;
EDGE[i].nVal = 999999;
return nRetn;
}
}
}
/***********************
Description: 恢复边权值
***********************/
void Recover(int A, int B, int nR) {
for (int i = head[A]; i != 0; i = EDGE[i].nPre) {
if (EDGE[i].nTo == B) {
EDGE[i].nVal = nR;
break;
}
}
}
int ans = 0;
int main() {
scanf("%d %d", &N, &M);
for (int i = 1; i <= M; i++) {
scanf("%d %d %d", &x, &y, &c);
Add(x, y, c);
Add(y, x, c);
}
SPFA(1);
int nMin = dis[N];
Is[1] = true;
_A[0] = 1;
DFS(1, 0, 1, nMin);
//枚举最短路中的每条边
int i = 0;
while (true) {
if (i == N) break;
int A = _A[i], B = _A[i + 1];
int nRetn = Change(A, B);
SPFA(1);
ans = max(ans, dis[N]);
Recover(A, B, nRetn);
i ++;
}
cout << ans << endl;
return 0;
}
SPFA记录最短路径
:申请一个nPre数组, 在进行松弛操作的时候,记录下当前点的前驱, 最后倒序输出即最短路径.
For example:
int SPFA(int nStart) {
memset(dis, 0x7, sizeof(dis));
Q.push(nStart);
IsStack[nStart] = true;
dis[nStart] = 0;
while (!Q.empty()) {
int nPoint = Q.front();
Q.pop();
IsStack[nPoint] = false;
for (int i = head[nPoint]; i != 0; i = EDGE[i].nPre) {
int nNextPoint = EDGE[i].nTo;
if (dis[nPoint] + EDGE[i].nVal < dis[nNextPoint]) {
dis[nNextPoint] = dis[nPoint] + EDGE[i].nVal;
//这里记录下前驱
nPre[nNextPoint] = nPoint;
if (!IsStack[nNextPoint]) {
IsStack[nNextPoint] = true;
Q.push(nNextPoint);
}
}
}
}
}
/*
* Copyright © Eliot
* Date: 2016-10-26
* Author: Eliot
* QQ: 1161142536
* Description: 100分 玛丽卡
*/
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
#define MAX 1001
int N = 0, M = 0;
int x = 0, y = 0, c = 0;
/***********************
Description: 邻接表
***********************/
struct STRUCT {
int nPre;
int nTo;
int nVal;
}EDGE[1000 * MAX];
int head[MAX] = { 0 };
int nCount = 0;
/***********************
Description: 添边
***********************/
void Add(int a, int b, int c) {
EDGE[++nCount].nTo = b;
EDGE[nCount].nVal = c;
EDGE[nCount].nPre = head[a];
head[a] = nCount;
}
/******************************************************
Description: SPFA最短路, 在其中判断 A, B 是否可以相连
******************************************************/
queue<int> Q;
int dis[MAX] = { 0 };
int nPre[MAX] = { 0 };
bool IsStack[MAX] = { false };
int SPFA(int nStart, int A, int B) {
memset(dis, 0x7, sizeof(dis));
Q.push(nStart);
IsStack[nStart] = true;
dis[nStart] = 0;
while (!Q.empty()) {
int nPoint = Q.front();
Q.pop();
IsStack[nPoint] = false;
for (int i = head[nPoint]; i != 0; i = EDGE[i].nPre) {
int nNextPoint = EDGE[i].nTo;
if ((nPoint == A && nNextPoint == B) || (nPoint == B && nNextPoint == A)) continue ;
if (dis[nPoint] + EDGE[i].nVal < dis[nNextPoint]) {
dis[nNextPoint] = dis[nPoint] + EDGE[i].nVal;
nPre[nNextPoint] = nPoint;
if (!IsStack[nNextPoint]) {
IsStack[nNextPoint] = true;
Q.push(nNextPoint);
}
}
}
}
}
int ans = 0;
int Arr[MAX] = { 0 }, C = 0;
int main() {
scanf("%d %d", &N, &M);
for (int i = 1; i <= M; i++) {
scanf("%d %d %d", &x, &y, &c);
Add(x, y, c);
Add(y, x, c);
}
SPFA(1, -1, -1);
int nMin = dis[N];
//记录路径
int P = N;
while (P != 1) {
Arr[++C] = nPre[P];
P = nPre[P];
}
C ++;
Arr[0] = N;
//枚举最短路中的每一条边
for (int i = 0; i < C - 1; i++) {
int A = Arr[i], B = Arr[i + 1];
SPFA(1, A, B);
ans = max(ans, dis[N]);
}
cout << ans << endl;
return 0;
}