题目:
http://acm.hdu.edu.cn/showproblem.php?pid=5294
题意:
给一个图,2000点,60000边,图中存在多条权值相同的1->n的最短路,第一个问题:删去多少条边后,1->n的最短路径变长;第二个问题:求1->n最短路中,经过节点最少的最短路径的节点数
思路:
在spfa算法中加入一个siz数组,siz[v]记录起点到v点的最短路径经过了多少个节点,即可求出第二个问题的解;
求第二问时得到的dis数组存储了每个点到起点的距离,用这个数组构建新图,把所有最短路上的点和边加入到新图中,所有边的容量记为1,将起点视为源点,终点视为汇点,问题转变成求新图的最小割,即源点到汇点的最大流,最大流算法选择EK会超时,改用dinic后可过
代码:
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<functional>
#pragma comment(linker, "/STACK:102400000,102400000")//C++
using namespace std;
const double PI = 3.141592653589793238462643383279502884197169399;
const int MAXINT = 0x7fffffff;
const int MAXSIZE = 2000 + 5;
const long long INF = 0x7FFFFFFFFFFFFFFF;
int n,m;
//vector<int> e[MAXSIZE], len[MAXSIZE];
int first[MAXSIZE], gnext[120005], to[120005], wei[120005], edge;
int d[MAXSIZE];
int siz[MAXSIZE];
void init(){
memset(siz,0,sizeof(siz));
memset(d,0x1f,sizeof(d));
memset(first, 0, sizeof(first));
edge = 0;
}
void g_insert(int a, int b, int c){
gnext[++edge] = first[a];
first[a] = edge;
to[edge] = b;
wei[edge] = c;
}
void spfa(int s,int t){
queue<int> Q;
while (!Q.empty()) Q.pop();
bool visit[MAXSIZE] = { 0 };
d[s] = 0;
visit[s] = true;
siz[s] = 1;
Q.push(s);
while (!Q.empty()){
int v = Q.front();
Q.pop();
visit[v] = false;
int j=first[v];
while (j){
int u = to[j];
if (d[u] > d[v] + wei[j]){
d[u] = d[v] + wei[j];
siz[u] = siz[v] + 1;
if (!visit[u]){
Q.push(u);
visit[u] = true;
}
}
else if (d[u] == d[v] + wei[j]){
siz[u] = min(siz[u], siz[v]+1);
}
j = gnext[j];
}
}
return;
}
struct Edge{
int from, to, cap;
};
vector<Edge> edges; //边表,edges[e]和edges[e^1]互为反向边
vector<int> G[MAXSIZE]; //邻接表
int s, t; //结点数,边数,源汇点
bool vis[MAXSIZE];
int di[MAXSIZE]; //层次记录
int cur[MAXSIZE]; //该节点正要考虑的弧的下标
void AddEdge(int from, int to, int cap){
Edge e = { from, to, cap };
edges.push_back(e);
G[from].push_back(edges.size() - 1);
}
void createNewG(){
for (int i=1;i<=n;++i) G[i].clear();
edges.clear();
for (int i=1;i<=n;++i){
int j=first[i];
while (j){
int v=to[j];
if (d[v] == d[i] + wei[j]){
AddEdge(i, v, 1);
AddEdge(v, i, 0);
}
j = gnext[j];
}
}
s=1;
t=n;
}
bool BFS(){
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(s);
di[s] = 0;
vis[s] = true;
while (!Q.empty()) {
int x = Q.front();
Q.pop();
for (int i = 0; i < G[x].size(); ++i) {
Edge& e = edges[G[x][i]];
if (!vis[e.to] && e.cap) {
vis[e.to] = true;
di[e.to] = di[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x, int a){
if (x == t || a == 0) return a;
int flow = 0, f;
for (int& i = cur[x]; i < G[x].size(); ++i){
Edge& e = edges[G[x][i]];
if (di[x] + 1 == di[e.to] && (f = DFS(e.to, min(a, e.cap)))>0){
e.cap -= f;
edges[G[x][i] ^ 1].cap += f;
flow += f;
a -= f;
if (a == 0) break;
}
}
return flow;
}
int Maxflow() {
int flow = 0;
while (BFS()){
memset(cur, 0, sizeof(cur));
flow += DFS(s, MAXSIZE);
}
return flow;
}
int main(){
int a,b,c;
while (scanf("%d %d",&n,&m)!=EOF){
init();
for (int i=0;i<m;++i){
scanf("%d %d %d",&a,&b,&c);
g_insert(a,b,c);
g_insert(b,a,c);
}
spfa(1,n);
createNewG();
int temp;
temp = Maxflow();
cout<<temp<<" "<<m-(siz[n]-1)<<endl;
}
return 0;
}