题目大意
给定一个图,给你n个人的起点,同时出发,不允许两个人同时通过同一条边的同一个方向,所有人必须走最短路径,问满足这种情况的最多的人数。
解答
首先先用SPFA求出最短路图,然后对每一个到终点相同距离的人拎出来做网络流,然后将每次求出的最大流求和就可以了。
附上AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXM = 150005;
const int MAXN = 100000;
const int oo = 2147483647;
inline int getint()
{
int ans = 0;
char w = getchar();
while (w < '0' || w > '9')
w = getchar();
while ('0' <= w && w <= '9') {
ans = ans * 10 + w - '0';
w = getchar();
}
return ans;
}
class Edge
{
public:
int to;
int len;
int next;
};
class PEdge
{
public:
int to;
int from;
int len;
int next;
};
Edge es[MAXM];
Edge ces[MAXN];
int head[MAXN];
int h[MAXN];
int ch[MAXN];
PEdge ee[MAXM];
int person[MAXN];
int ph[MAXN];
int et = -1;
int cet = -1;
int pet = -1;
int st, th;
int fl[MAXN];
bool vis[MAXN];
int dis[MAXN];
int n, m, c;
bool cmp(int a, int b)
{
return dis[a] < dis[b];
}
void addEdge(int u, int v)
{
cet++;
ces[cet].to = v;
ces[cet].len = 1;
ces[cet].next = ch[u];
ch[u] = cet;
cet++;
ces[cet].to = u;
ces[cet].len = 0;
ces[cet].next = ch[v];
ch[v] = cet;
}
void add(int u, int v, int l)
{
pet++;
ee[pet].to = v;
ee[pet].from = u;
ee[pet].len = l;
ee[pet].next = ph[u];
ph[u] = pet;
pet++;
ee[pet].to = u;
ee[pet].from = v;
ee[pet].len = l;
ee[pet].next = ph[v];
ph[v] = pet;
}
void newEdge(int u, int v)
{
et++;
es[et].to = v;
es[et].len = 1;
es[et].next = h[u];
h[u] = et;
et++;
es[et].to = u;
es[et].len = 0;
es[et].next = h[v];
h[v] = et;
}
bool bfs()
{
memset(fl, 0, sizeof(fl));
queue<int> ser;
fl[st] = 1;
ser.push(st);
int root;
bool flag = false;
while (!ser.empty()) {
root = ser.front();
ser.pop();
for (int i = h[root]; i != -1; i = es[i].next)
if (es[i].len && !fl[es[i].to]) {
fl[es[i].to] = fl[root] + 1;
ser.push(es[i].to);
if (es[i].to == th)
flag = true;
}
}
return flag;
}
int dfs(int x, int flow)
{
if (x == th)
return flow;
int cflow = flow;
int ret;
for (int &i = head[x]; i != -1; i = es[i].next)
if (es[i].len && fl[es[i].to] == fl[x]+1) {
ret = dfs(es[i].to, min(flow, es[i].len));
es[i].len -= ret;
es[i^1].len += ret;
flow -= ret;
if (!flow)
return cflow;
}
return cflow-flow;
}
int dinic()
{
int ans = 0;
while(bfs()) {
for (int i = 1; i <= n+2; i++)
head[i] = h[i];
ans += dfs(st, oo);
}
return ans;
}
void SPFA(int s = 1)
{
queue<int> ser;
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; i++)
dis[i] = oo;
dis[s] = 0;
ser.push(s);
int root;
vis[s] = true;
while(!ser.empty()) {
root = ser.front();
ser.pop();
for (int i = ph[root]; i != -1; i = ee[i].next) {
if (dis[ee[i].to] > dis[root]+ee[i].len) {
dis[ee[i].to] = dis[root]+ee[i].len;
if (!vis[ee[i].to]) {
ser.push(ee[i].to);
vis[ee[i].to] = true;
}
}
}
vis[root] = false;
}
}
void check()
{
for (int i = 0; i < m*2; i++)
if (dis[ee[i].to] == dis[ee[i].from] + ee[i].len) {
addEdge(ee[i].to, ee[i].from);
}
}
void readin()
{
memset(h, -1, sizeof(h));
memset(ch, -1, sizeof(ch));
memset(ph, -1, sizeof(ph));
n = getint();
m = getint();
c = getint();
//scanf("%d %d %d", &n, &m, &c);
int x, y, z;
for (int i = 0; i < m; i++) {
//scanf("%d %d %d", &x, &y, &z);
x = getint();
y = getint();
z = getint();
add(x, y, z);
}
SPFA();
check();
for (int i = 0; i < c; i++) {
//scanf("%d", &x);
person[i] = getint();
}
sort(person, person+c, cmp);
th = 1;
st = n+2;
}
void setUp()
{
et = cet;
for (int i = 0; i <= n+2; i++)
h[i] = ch[i];
for (int i = 0; i <= cet; i++)
es[i] = ces[i];
}
void work()
{
int ans = 0;
int tmp = dis[person[0]];
setUp();
for (int i = 0; i < c; i++) {
if (dis[person[i]] == tmp) {
newEdge(st, person[i]);
} else {
ans += dinic();
setUp();
newEdge(st, person[i]);
tmp = dis[person[i]];
}
}
ans += dinic();
printf("%d", ans);
}
int main()
{
//freopen("input.in", "r", stdin);
readin();
work();
return 0;
}