http://acm.hdu.edu.cn/showproblem.php?pid=5294
题意:
1、最少须要切断多少边使吴不能找到张(题意吴仅仅能走最短路径上面的边),对从起点到终点的最短路径又一次建图,每条边的权值为1。求最大流就可以
2、在吴能够找到张的前提下,最多能够切断边的数量:仅仅须要在全部最短路径中寻找一条经过边数量最少的最短路径,用边的总数减去它就可以(逆向思维)
分析:
最短路径+最大流套模板
代码:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010 //点
#define MAXM 800010//边
#define inf 1000000000
using namespace std;
int N,M,s,t;
struct HeapNode //Dijkstra算法用到的优先队列的节点
{
int d,u,len;
HeapNode(int d,int u,int len):d(d),u(u),len(len){}
bool operator < (const HeapNode &rhs)const
{
if(d!=rhs.d||u!=rhs.u)
return d > rhs.d;
return len<rhs.len;
}
};
struct Edge //边
{
int from,to,dist;
Edge(int f,int t,int d):from(f),to(t),dist(d){}
};
struct Dijkstra
{
int n,m; //点数和边数,编号都从0开始
vector<Edge> edges; //边列表
vector<int> G[MAXN];//每个节点出发的边编号(从0开始编号)
bool done[MAXN]; //是否已永久标号
int d[MAXN]; //s到各个点的距离
int road[MAXN];
void init(int n)
{
this->n=n;
for(int i=0;i<n;i++) G[i].clear();//清空邻接表
edges.clear(); //清空边列表
}
void AddEdge(int from,int to,int dist)
{//如果是无向图,每条无向边调用两次AddEdge
edges.push_back(Edge(from,to,dist) );
m = edges.size();
G[from].push_back(m-1);
}
void dijkstra(int s)//求s到所有点的距离
{
priority_queue<HeapNode> Q;
for(int i=0;i<n;i++) d[i]=inf;
d[s]=0;
road[s]=0;
memset(done,0,sizeof(done));
Q.push(HeapNode(0,s,0) );
while(!Q.empty())
{
HeapNode x=Q.top(); Q.pop();
int u=x.u;
if(done[u]) continue;
done[u]= true;
for(int i=0;i<G[u].size();i++)
{
Edge& e= edges[G[u][i]];
if(d[e.to]> d[u]+e.dist)
{
d[e.to] = d[u]+e.dist;
road[e.to]=road[u]+1;
Q.push(HeapNode(d[e.to],e.to,road[u]+1) );
}
else
if(d[e.to]==d[u]+e.dist)
{
if(road[u]+1<road[e.to]){
d[e.to] = d[u]+e.dist;
road[e.to]=road[u]+1;
Q.push(HeapNode(d[e.to],e.to,road[u]+1) );
}
}
}
}
}
}DJ;
struct Node
{
int from,to,next;
int cap;
}edge[MAXM];
int tol;
int head[MAXN];
int dep[MAXN];
int gap[MAXN];//gap[x]=y :说明残留网络中dep[i]==x的个数为y
//int n;//n是总的点的个数,包括源点和汇点
void init()
{
tol=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w)
{
edge[tol].from=u;
edge[tol].to=v;
edge[tol].cap=w;
edge[tol].next=head[u];
head[u]=tol++;
edge[tol].from=v;
edge[tol].to=u;
edge[tol].cap=0;
edge[tol].next=head[v];
head[v]=tol++;
}
void BFS(int start,int end)
{
memset(dep,-1,sizeof(dep));
memset(gap,0,sizeof(gap));
gap[0]=1;
int que[MAXN];
int front,rear;
front=rear=0;
dep[end]=0;
que[rear++]=end;
while(front!=rear)
{
int u=que[front++];
if(front==MAXN)front=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(dep[v]!=-1)continue;
que[rear++]=v;
if(rear==MAXN)rear=0;
dep[v]=dep[u]+1;
++gap[dep[v]];
}
}
}
int ISAP(int start,int end)
{
int res=0;
BFS(start,end);
int cur[MAXN];
int S[MAXN];
int top=0;
memcpy(cur,head,sizeof(head));
int u=start;
int i;
while(dep[start]<N)
{
if(u==end)
{
int temp=inf;
int inser;
for(i=0;i<top;i++)
if(temp>edge[S[i]].cap)
{
temp=edge[S[i]].cap;
inser=i;
}
for(i=0;i<top;i++)
{
edge[S[i]].cap-=temp;
edge[S[i]^1].cap+=temp;
}
res+=temp;
top=inser;
u=edge[S[top]].from;
}
if(u!=end&&gap[dep[u]-1]==0)//出现断层,无增广路
break;
for(i=cur[u];i!=-1;i=edge[i].next)
if(edge[i].cap!=0&&dep[u]==dep[edge[i].to]+1)
break;
if(i!=-1)
{
cur[u]=i;
S[top++]=i;
u=edge[i].to;
}
else
{
int min=N;
for(i=head[u];i!=-1;i=edge[i].next)
{
if(edge[i].cap==0)continue;
if(min>dep[edge[i].to])
{
min=dep[edge[i].to];
cur[u]=i;
}
}
--gap[dep[u]];
dep[u]=min+1;
++gap[dep[u]];
if(u!=start)u=edge[S[--top]].from;
}
}
return res;
}
int main()
{
int i,j,x,y,z,ant;
while(~scanf("%d%d",&N,&M))
{
DJ.init(N);
for(i=0;i<M;i++)
{
scanf("%d%d%d",&x,&y,&z);
if(x==y)continue;
DJ.AddEdge(x-1,y-1,z);
DJ.AddEdge(y-1,x-1,z);
}
DJ.dijkstra(0);
ant=M-DJ.road[N-1];
init();
M=DJ.edges.size();
for(i=0;i<M;i++)
{
x=DJ.edges[i].from;
y=DJ.edges[i].to;
z=DJ.edges[i].dist;
if(DJ.d[y]==DJ.d[x]+z)
addedge(x,y,1);
}
printf("%d %d\n",ISAP(0,N-1),ant);
}
}