题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6582
题意:现在有一个有向图,每个边有个边权,你需要拆除一些边使 1 1 1到 n n n的最短路变长并且拆除边的权值总和最小。
解题心得:首先将 1 1 1到 n n n的所有最短路上用到的边都找出来形成一个新的图,然后就是一个最小割。找出所有最短路径用到的边可以将 1 1 1到所有点的最短路径答案找到,然后再从 n n n点反过来找到转移的边。当时真的时不敢相信第一个签到题是最小割,结果还真是。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+100;
int n, m;
ll dis[maxn];
bool vis[maxn];
struct Edge {
ll cap, to, rev;
};
vector <Edge> ve[maxn], reverse_ve[maxn];//ve用来记录原本的图,reverse_ve用来记录将边反向后的图
vector <Edge> maps[maxn];//记录所有最短路径用到的边形成的新图
void init() {
scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++) {
ve[i].clear();
reverse_ve[i].clear();
maps[i].clear();
dis[i] = LLONG_MAX/3;
vis[i] = false;
}
for(int i=1;i<=m;i++) {
ll a, b, c; scanf("%lld%lld%lld", &a, &b, &c);
ve[a].push_back({c, b, 0});
reverse_ve[b].push_back({c, a, 0});
}
}
void spfa() {//得到1点到所有点的最短路径
queue <int> qu;
dis[1] = 0;
qu.push(1);
while(!qu.empty()) {
int now = qu.front(); qu.pop();
vis[now] = false;
for(int i=0;i<ve[now].size();i++) {
Edge e = ve[now][i];
ll to = e.to;
ll cap = e.cap;
if(dis[to] > dis[now] + cap) {
dis[to] = dis[now] + cap;
if(!vis[to]) {
vis[to] = true;
qu.push(to);
}
}
}
}
}
void get_new_map() {//得到新图
queue <int> qu;
qu.push(n);
while(!qu.empty()) {
int now = qu.front(); qu.pop();
for(int i=0;i<reverse_ve[now].size();i++) {
int to = reverse_ve[now][i].to;
int cap = reverse_ve[now][i].cap;
if(dis[to] + cap == dis[now]) {
if(!vis[to]) {
qu.push(to);
vis[to] = true;
}
maps[to].push_back({cap, now, maps[now].size()});
maps[now].push_back({0, to, maps[to].size()-1});
}
}
}
}
//以下是最大流的板子
ll level[maxn], iter[maxn];
void bfs(int s) {
memset(level, -1, sizeof(level));
queue <int> qu;
level[s] = 0;
qu.push(s);
while(!qu.empty()) {
int v = qu.front(); qu.pop();
for(int i=0;i<maps[v].size();i++) {
Edge &e = maps[v][i];
if(e.cap > 0 && level[e.to] < 0) {
level[e.to] = level[v] + 1;
qu.push(e.to);
}
}
}
}
ll dfs(ll v, ll t, ll f) {
if(v == t) return f;
for(ll &i=iter[v]; i<maps[v].size();i++) {
Edge &e = maps[v][i];
if(e.cap > 0 && level[v] < level[e.to]) {
ll d = dfs(e.to, t, min(f, e.cap));
if(d > 0) {
e.cap -= d;
maps[e.to][e.rev].cap += d;
return d;
}
}
}
return 0;
}
ll max_flow() {
ll flow = 0;
while(true) {
bfs(1);
if(level[n] < 0) return flow;
memset(iter, 0, sizeof(iter));
ll f = 0;
while(true) {
f = dfs(1, n, LLONG_MAX/3);
if(f <= 0) break;
flow += f;
}
}
}
int main() {
// freopen("1.in.txt", "r", stdin);
int t; scanf("%d", &t);
while(t--) {
init();
spfa();
get_new_map();
printf("%lld\n", max_flow());
}
return 0;
}