http://acm.hdu.edu.cn/showproblem.php?pid=3416
题意:
A要去B,有很多路,A要走最短路,每次走过就不能再走了,问有几种走法
思路:
首先题目上给了很多路,但有些路是不需要的,因为走最短路的时候不会走到它,所以要被这些路给剔除掉。怎么剔除呢,可以先跑一下最短路,把最短路可以走的边建到最大流的边里,权值为1,那么这样不走的边就不会建到里面。
那么怎么用最短路把能走边给标记出来呢,因为最短路中两个相连的点之间的距离恰好是距源点S的距离之差,这样只需要跑一边啊最短路就可以把边给建好^-^
如图所示,因为dis[3]-dis[1]!=3所以1->3这条边不是最短路的边
但是存边的时候不能用矩阵存,会WA,原因我还没找到,很难受的说。
#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <stdio.h>
#include <deque>
using namespace std;
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define maxn 1000005
#define eps 0.00000001
#define PI acos(-1.0)
#define M 1000000007
struct Edge {
int v, w, nxt;
}edge[maxn];
struct Link{
int v, dis;
Link(){}
Link(int _v, int _dis) {
v = _v; dis = _dis;
}
};
vector<Link> vec[1005];
int head[maxn], tot, S, T, dis[maxn], cur[maxn], vis[maxn], aug[maxn],pre[maxn], gap[maxn];
int n, m;
void addEdge(int u, int v, int w) {
edge[tot].v = v;
edge[tot].w = w;
edge[tot].nxt = head[u];
head[u] = tot ++;
edge[tot].v = u;
edge[tot].w = 0;
edge[tot].nxt = head[v];
head[v] = tot ++;
}
void init() {
tot = 0;
memset(head, -1, sizeof(head));
}
//Dijkstra
void Dijkstra() {
memset(vis, 0, sizeof(vis));
memset(dis, INF, sizeof(dis));
dis[S] = 0;
for (int i = 1; i <= n; i ++) {
int u = -1, MinDis = INF;
for (int j = 1; j <= n; j ++)
if(!vis[j] && MinDis > dis[j]) {
MinDis = dis[j];
u = j;
}
if(u == -1) break;
vis[u] = 1;
for (int j = 0; j < (int)vec[u].size(); j ++) {
Link t = vec[u][j];
if(!vis[t.v] && dis[t.v] > dis[u] + t.dis)
dis[t.v] = dis[u] + t.dis;
}
}
}
/* //SPFA
void SPFA() {
queue<int> q;
memset(dis, INF, sizeof(dis));
dis[S] = 0;//起始点
memset(vis, 0, sizeof(vis));//全赋初值
q.push(S);
vis[S] = 1;//如队列就标记
while(!q.empty()) {
int x = q.front(); q.pop();//队列头拿出
vis[x] = 0;//取消标记
for (int j = 0; j < vec[x].size(); j ++) {//松弛相关点
Link t = vec[x][j];
if (dis[t.v] > dis[x] + t.dis) {
dis[t.v] = dis[x] + t.dis;
if (!vis[t.v]) {//如果此时这个点不在队列中,如队
vis[t.v] = 1;//并标记
q.push(t.v);//如对
}
}
}
}
}
*/
/*
//dinic
int bfs() {
memset(dis, -1, sizeof(dis));
dis[T] = 0;
queue<int> que;
que.push(T);
while(!que.empty()) {
int u = que.front(); que.pop();
for (int i = head[u]; i + 1; i = edge[i].nxt) {
if(dis[edge[i].v] == -1 && edge[i ^ 1].w > 0) {
dis[edge[i].v] = dis[u] + 1;
que.push(edge[i].v);
}
}
}
return dis[S] != -1;
}
int dfs(int u, int flow) {
if(u == T) return flow;
int belta = flow;
for (int &i = cur[u]; i + 1; i = edge[i].nxt) {
if(dis[u] == dis[edge[i].v] + 1 && edge[i].w > 0) {
int d = dfs(edge[i].v, min(belta, edge[i].w));
edge[i].w -= d; edge[i ^ 1].w += d;
belta -= d;
if(belta == 0) break;
}
}
return flow - belta;
}
int dinic() {
int ans = 0;
while(bfs()) {
for (int i = 1; i <= n; i ++)
cur[i] = head[i];
ans += dfs(S, INF);
}
return ans;
}
*/
//SAP
int SAP(int n){
int max_flow = 0,u = S, v;
int id, mindep;
aug[S] = INF;
pre[S] = -1;
memset(dis, 0, sizeof(dis));
memset(gap, 0, sizeof(gap));
gap[0] = n;
for(int i = 0; i <= n; i ++)
cur[i] = head[i];
while(dis[S] < n){
int flag = 0;
if(u == T){
max_flow += aug[T];
for(v= pre[T]; v + 1; v = pre[v]){
id = cur[v];
edge[id].w -= aug[T];
edge[id^1].w += aug[T];
aug[v] -= aug[T];
if(edge[id].w == 0)
u = v;
}
}
for(int i = cur[u]; i != -1; i = edge[i].nxt){
v = edge[i].v;
if(edge[i].w > 0 && dis[u] == dis[v] + 1){
flag = 1;
pre[v] = u;
cur[u] = i;
aug[v] = min(aug[u], edge[i].w);
u = v;
break;
}
}
if(!flag){
if(--gap[dis[u]] == 0)
break;
mindep = n;
cur[u] = head[u];
for(int i = head[u]; i != -1; i = edge[i].nxt){
v = edge[i].v;
if(edge[i].w > 0 && dis[v] < mindep){
mindep = dis[v];
cur[u] = i;
}
}
dis[u] = mindep + 1;
gap[dis[u]] ++;
if(u != S)
u = pre[u];
}
}
return max_flow;
}
int main(int argc, const char * argv[]) {
int TT;
scanf("%d", &TT);
while(TT --) {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i ++)
vec[i].clear();
for (int i = 0; i < m; i ++) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
vec[u].push_back(Link(v, w));
}
scanf("%d %d", &S, &T);
Dijkstra();
if(dis[T] == 0){
printf("0\n");
continue;
}
init();
for (int i = 1; i <= n; i ++) {
for (int j = 0; j < (int)vec[i].size(); j ++) {
Link t = vec[i][j];
if(dis[i] + t.dis == dis[t.v])
addEdge(i, t.v, 1);
}
}
printf("%d\n", SAP(n + 1));
}
return 0;
}