给出一个图, 问从起点到终点, 问去掉一些边使得最短路增大, 求最少的花费是多少(6582是边长, 1266是给定的).
另外, 6582是有向边, 1266是无向边.
这个题可以分解成两部分:
Ⅰ求出最短路所有路径上的边
Ⅱ在Ⅰ上新建一个图, 跑网络流最小割.
最小割: 就是把起点和汇点割开的最小花费.
这样, 就是花费最少的代价, 把所有的最短路径割断, 进而增大了最短路.
Ⅰ就是检查每一条边u→v, s→u+len[u→v]是否=s→v, 如果是的话, 它就可能是最短路上的点(是最短路上的点, 但这个最短路可能不是到终点的).
6582
#include<bits/stdc++.h>
using namespace std;
void debug_out() { cerr << '\n'; }
template<typename T, typename ...R>
void debug_out(const T &f, const R &...r) {
cerr << f << " ";
debug_out(r...);
}
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);
typedef long long ll;
typedef pair<int, ll> pil;
inline ll read() {
ll x = 0;
int f = 0;
char ch = getchar();
while (ch < '0' || ch > '9') f |= (ch == '-'), ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x = f ? -x : x;
}
inline void write(ll x) {
if (x == 0) {
putchar('0'), putchar('\n');
return;
}
if (x < 0) {
putchar('-');
x = -x;
}
static char s[23];
int l = 0;
while (x != 0)s[l++] = x % 10 + 48, x /= 10;
while (l)putchar(s[--l]);
putchar('\n');
}
int lowbit(int x) { return x & (-x); }
template<class T>
T big(const T &a1, const T &a2) { return a1 > a2 ? a1 : a2; }
template<typename T, typename ...R>
T big(const T &f, const R &...r) { return big(f, big(r...)); }
template<class T>
T sml(const T &a1, const T &a2) { return a1 < a2 ? a1 : a2; }
template<typename T, typename ...R>
T sml(const T &f, const R &...r) { return sml(f, sml(r...)); }
const int M = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
int _;
struct edge {
int u, v, nxt;
ll w;
} edgesSP[M];
int ei;
int head[M];
ll disFromS[M];
ll disFromT[M];
int s, t;
int n;
int vis[M];
namespace SP {
void init() {
ei = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, ll w) {
edgesSP[ei].u = u, edgesSP[ei].v = v, edgesSP[ei].w = w, edgesSP[ei].nxt = head[u];
head[u] = ei++;
}
void shortPath(int s, ll *dis) {
memset(vis, 0, sizeof(vis));
fill(dis, dis + n + 1, INF);
dis[s] = 0;
queue<pil> q;
q.push(make_pair(s, 0));
while (!q.empty()) {
pil now = q.front();
q.pop();
int d = now.second;
int u = now.first;
// debug(u, d);
if (vis[u])continue;
vis[u] = 1;
for (int i = head[u]; i != -1; i = edgesSP[i].nxt) {
int v = edgesSP[i].v;
if (dis[v] > dis[u] + edgesSP[i].w) {
dis[v] = dis[u] + edgesSP[i].w;
q.push(make_pair(v, dis[v]));
}
}
}
}
}
namespace DINIC {
const int MAXN = 1e5 + 5;//点数的最大值
const int MAXM = 1e5 + 5;//边数的最大值
struct Edge {
int to, next;
ll cap, flow;
} edge[MAXM * 2]; //注意是 MAXM
int tol;
int head[MAXN];
void init() {
tol = 2;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, ll w, ll rw = 0) {
edge[tol].to = v;
edge[tol].cap = w;
edge[tol].flow = 0;
edge[tol].next = head[u];
head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = rw;//无向图不要建4次边, 把反向边流量也设成w
edge[tol].flow = 0;
edge[tol].next = head[v];
head[v] = tol++;
}
int Q[MAXN];
int dep[MAXN], cur[MAXN], sta[MAXN];
bool bfs(int s, int t, int n) {//bfs分层
int front = 0, tail = 0;
memset(dep, -1, sizeof(dep[0]) * (n + 1));
dep[s] = 0;
Q[tail++] = s;
while (front < tail) {
int u = Q[front++];
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (edge[i].cap > edge[i].flow && dep[v] == -1) {
dep[v] = dep[u] + 1;
if (v == t)
return true;
Q[tail++] = v;
}
}
}
return false;
}
ll dinic(int s, int t, int n) {
ll maxflow = 0;
while (bfs(s, t, n)) {
for (int i = 1; i <= n; i++)//下标从0开始/从1开始
cur[i] = head[i];
int u = s, tail = 0;
while (cur[s] != -1)///栈模拟dfs
{
// printf("%d %d %lld\n",s,cur[s],maxflow);
if (u == t) {//走到了t点
ll tp = INF;
for (int i = tail - 1; i >= 0; i--)
tp = std::min(tp, edge[sta[i]].cap - edge[sta[i]].flow);
maxflow += tp;
for (int i = tail - 1; i >= 0; i--) {
edge[sta[i]].flow += tp;
edge[sta[i] ^ 1].flow -= tp;
if (edge[sta[i]].cap - edge[sta[i]].flow == 0)
tail = i;
}
u = edge[sta[tail] ^ 1].to;
} else if (cur[u] != -1
&& edge[cur[u]].cap > edge[cur[u]].flow
&& dep[u] + 1 == dep[edge[cur[u]].to]) {//如果还没走到t, 并且还能走,那就继续dfs
sta[tail++] = cur[u];
u = edge[cur[u]].to;
} else {//如果走不了了, 那就返回到上一层
while (u != s && cur[u] == -1)
u = edge[sta[--tail] ^ 1].to;
cur[u] = edge[cur[u]].next;
}
}
}
return maxflow;
}
}
struct node {
int u, v;
ll w;
} edgeOnGraphBF[M];
int main() {
_ = read();
while (_--) {
n = read();
int m;
m = read();
SP::init();
for (int i = 0; i < m; ++i) {
int u = read(), v = read();
ll w = read();
edgeOnGraphBF[i] = node{u, v, w};
// edgeOnGraphBF[i] = node{v, u, w};
SP::addedge(u, v, w);
// SP::addedge(v, u, w);
}
SP::shortPath(1, disFromS);
// debug(disFromS[n]);
SP::init();
for (int i = 0; i < m; ++i) {
int u = edgeOnGraphBF[i].v, v = edgeOnGraphBF[i].u;
ll w = edgeOnGraphBF[i].w;
SP::addedge(u, v, w);
}
SP::shortPath(n, disFromT);
// debug(disFromT[1]);
queue<node> q;//最短路上的边, 要拿来跑最大流
for (int i = 0; i < m; ++i) {
node now = edgeOnGraphBF[i];
if (disFromS[now.u] + now.w == disFromS[now.v])
// if (disFromS[now.u] + now.w + disFromT[now.v] == disFromT[1])
q.push(now);
}
if (q.empty()) {
printf("0\n");
continue;
}
DINIC::init();
while (!q.empty()) {
DINIC::addedge(q.front().u, q.front().v, q.front().w);
q.pop();
}
printf("%lld\n", DINIC::dinic(1, n, n));
}
return 0;
}
1266:
/**************************************************************
Problem: 1266
User: swqeaaa
Language: C++
Result: Accepted
Time:340 ms
Memory:36144 kb
****************************************************************/
#include<bits/stdc++.h>
using namespace std;
void debug_out() { cerr << '\n'; }
template<typename T, typename ...R>
void debug_out(const T &f, const R &...r) {
cerr << f << " ";
debug_out(r...);
}
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<int, ll> pil;
inline ll read() {
ll x = 0;
int f = 0;
char ch = getchar();
while (ch < '0' || ch > '9') f |= (ch == '-'), ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x = f ? -x : x;
}
inline void write(ll x) {
if (x == 0) {
putchar('0'), putchar('\n');
return;
}
if (x < 0) {
putchar('-');
x = -x;
}
static char s[23];
int l = 0;
while (x != 0)s[l++] = x % 10 + 48, x /= 10;
while (l)putchar(s[--l]);
putchar('\n');
}
int lowbit(int x) { return x & (-x); }
template<class T>
T big(const T &a1, const T &a2) { return a1 > a2 ? a1 : a2; }
template<typename T, typename ...R>
T big(const T &f, const R &...r) { return big(f, big(r...)); }
template<class T>
T sml(const T &a1, const T &a2) { return a1 < a2 ? a1 : a2; }
template<typename T, typename ...R>
T sml(const T &f, const R &...r) { return sml(f, sml(r...)); }
const int M = 212345;// 2e5+5
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;// 1e9+7
int n;
// update on 2019/7/25
namespace SP {
//点数n要开全局
//记得初始化init, 以及是否为双向边
const int MAXN = M;//点数的最大值
const int MAXM = M;//边数的最大值
struct edge {
int u, v, nxt;
ll w;
ll c;
} edgesSP[/*边数*/MAXM * 2];
int ei;
int head[MAXN];
ll dis[MAXN];
int vis[MAXN];
void init() {
ei = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, ll w, ll c) {
edgesSP[ei].u = u, edgesSP[ei].v = v, edgesSP[ei].w = w, edgesSP[ei].c = c, edgesSP[ei].nxt = head[u];
head[u] = ei++;
}
struct qnode {
int first;
ll second;
bool operator<(const qnode a) const {
return second > a.second;
}
};
void shortPath(int s) {
memset(vis, 0, sizeof(vis));
fill(dis, dis + M, INF);
dis[s] = 0;
// queue<pil> q;
priority_queue<qnode> q;
q.push({s, 0});
while (!q.empty()) {
qnode now = q.top();
q.pop();
ll d = now.second;//dij里面这个没用, 是prim求生成树用的.
int u = now.first;
if (vis[u])continue;
vis[u] = 1;
for (int i = head[u]; i != -1; i = edgesSP[i].nxt) {
int v = edgesSP[i].v;
if (dis[v] > dis[u] + edgesSP[i].w) {
dis[v] = dis[u] + edgesSP[i].w;
q.push({v, dis[v]});
}
}
}
}
}
namespace DINIC {
//记得初始化init, 以及是否为双向边
const int MAXN = 3e5 + 5;//点数的最大值
const int MAXM = 3e5 + 5;//边数的最大值
struct Edge {
int to, next;
ll cap, flow;
} edge[MAXM * 2]; //注意是 MAXM
int tol;
int head[MAXN];
void init() {
tol = 2;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, ll w, ll rw = 0) {
edge[tol].to = v;
edge[tol].cap = w;
edge[tol].flow = 0;
edge[tol].next = head[u];
head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = rw;//无向图不要建4次边, 把反向边流量也设成w
// edge[tol].cap = w;//无向图不要建4次边, 把反向边流量也设成w
edge[tol].flow = 0;
edge[tol].next = head[v];
head[v] = tol++;
}
int Q[MAXN];
int dep[MAXN], cur[MAXN], sta[MAXN];
bool bfs(int s, int t, int n) {//bfs分层
int front = 0, tail = 0;
memset(dep, -1, sizeof(dep[0]) * (n + 1));
dep[s] = 0;
Q[tail++] = s;
while (front < tail) {
int u = Q[front++];
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (edge[i].cap > edge[i].flow && dep[v] == -1) {
dep[v] = dep[u] + 1;
if (v == t)
return true;
Q[tail++] = v;
}
}
}
return false;
}
int dinic(int s, int t, int n) {
ll maxflow = 0;
while (bfs(s, t, n)) {
for (int i = 1; i <= n; i++)//下标从0开始/从1开始
cur[i] = head[i];
int u = s, tail = 0;
while (cur[s] != -1)///栈模拟dfs
{
// printf("%d %d %lld\n",s,cur[s],maxflow);
if (u == t) {//走到了t点
ll tp = INF;
for (int i = tail - 1; i >= 0; i--)
tp = std::min(tp, edge[sta[i]].cap - edge[sta[i]].flow);
maxflow += tp;
for (int i = tail - 1; i >= 0; i--) {
edge[sta[i]].flow += tp;
edge[sta[i] ^ 1].flow -= tp;
if (edge[sta[i]].cap - edge[sta[i]].flow == 0)
tail = i;
}
u = edge[sta[tail] ^ 1].to;
} else if (cur[u] != -1
&& edge[cur[u]].cap > edge[cur[u]].flow
&& dep[u] + 1 == dep[edge[cur[u]].to]) {//如果还没走到t, 并且还能走,那就继续dfs
sta[tail++] = cur[u];
u = edge[cur[u]].to;
} else {//如果走不了了, 那就返回到上一层
while (u != s && cur[u] == -1)
u = edge[sta[--tail] ^ 1].to;
cur[u] = edge[cur[u]].next;
}
}
}
return maxflow;
}
}
void init() {
n = read();
int m = read();
SP::init();
for (int i = 0; i < m; ++i) {
int u = read(), v = read();
ll t = read(), c = read();
SP::addedge(u, v, t, c);
SP::addedge(v, u, t, c);
}
SP::shortPath(1);
write(SP::dis[n]);
DINIC::init();
for (int i = 1; i <= n; i++) {
// debug(i);
for (int j = SP::head[i]; j != -1; j = SP::edgesSP[j].nxt) {
// debug(j);
if (SP::dis[i] + SP::edgesSP[j].w == SP::dis[SP::edgesSP[j].v]) {
DINIC::addedge(i, SP::edgesSP[j].v, SP::edgesSP[j].c);
}
}
}
write(DINIC::dinic(1, n, n));
}
void solve() {
}
int main() {
init();
solve();
return 0;
}