hdu3416——最短路+最大流

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3416

Do not sincere non-interference。
Like that show, now starvae also take part in a show, but it take place between city A and B. Starvae is in city A and girls are in city B. Every time starvae can get to city B and make a data with a girl he likes. But there are two problems with it, one is starvae must get to B within least time, it's said that he must take a shortest path. Other is no road can be taken more than once. While the city starvae passed away can been taken more than once.


So, under a good RP, starvae may have many chances to get to city B. But he don't know how many chances at most he can make a data with the girl he likes . Could you help starvae?

Input

The first line is an integer T indicating the case number.(1<=T<=65)
For each case,there are two integer n and m in the first line ( 2<=n<=1000, 0<=m<=100000 ) ,n is the number of the city and m is the number of the roads.

Then follows m line ,each line have three integers a,b,c,(1<=a,b<=n,0<c<=1000)it means there is a road from a to b and it's distance is c, while there may have no road from b to a. There may have a road from a to a,but you can ignore it. If there are two roads from a to b, they are different.

At last is a line with two integer A and B(1<=A,B<=N,A!=B), means the number of city A and city B.
There may be some blank line between each case.

Output

Output a line with a integer, means the chances starvae can get at most.

Sample Input

3
7 8
1 2 1
1 3 1
2 4 1
3 4 1
4 5 1
4 6 1
5 7 1
6 7 1
1 7

6 7
1 2 1
2 3 1
1 3 3
3 4 1
3 5 1
4 6 1
5 6 1
1 6

2 2
1 2 1
1 2 2
1 2

Sample Output

2
1
1

不要真诚不干涉。‎
‎喜欢那个节目,现在明星也参加一个节目,但它发生在城市A和B之间。Starvae在城市A和女孩在城市B。每次Starvae可以到达城市B,并与他喜欢的女孩做数据。但有两个问题,一个是星华必须在最短的时间内到达B,据说他必须走最短的路。其他是没有道路可以采取不止一次。而城市之星去世可以不止一次。‎
‎因此,在一个好的RP下,Starvae可能有很多机会到达城市B。 ‎
‎ ‎
‎但他不知道有多少机会,他最多能与他喜欢的女孩做数据。你能帮starva吗?‎

‎输入‎

‎第一行是表示案例编号的整数 T。(1<_T<#65)‎
‎对于每种情况下,第一行中有两个整数 n 和 m(2<\n_lt;#1000,0_lt;_m_lt;#100000)是城市数,m 是道路数。‎
‎然后跟随 m 行,每行有三个整数 a、b、c、(1_lt;_a,b_lt;n,0_lt;c_lt;_lt;_lt;_1000)表示有一条从 a 到 b 的路,其距离为 c,而从 b 到 a 可能没有‎
‎道路。可能有一条路从一条路到一条路,但你可以忽略它。如果从 a 到 b 有两条道路,则它们是不同的。最后是一条包含两个整数 A 和 B(1_lt;#A,B_lt;_N,A!=B)的行,表示城市 A‎
‎和城市 B 的数量。每个案例之间可能存在一些空白行。 ‎
‎ ‎

‎输出‎

‎输出一个整数的线,意味着星形最多只能得到的机会。

 

题意其实就是让你求有几个最短路径。

首先我们需要清楚一个定理,如果一个边是最短路上的边,那么一定满足dis[e.from]+e.dis=dis[e.to];

之后就很好写了,也很经典了,

首先跑一个最短路,求出满足dis[e.from]+e.dis=dis[e.to]的边,即最短路上的边。

然后对每条最短路上的边建最大流边,容量为1,求出最大流即为结果。

不过最短路要用基于最小堆的DIjkstra算法实现,SPFA会超时。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1e5+7;
const int maxm=1e5+7;
struct Edge{
    int from,to;
    LL val;
};
struct HeapNode{
    LL d;           
    int u;
    bool operator < (const HeapNode & rhs) const{
		return d > rhs.d;
	}  
};
struct Dijstra{
    int n,m;
    vector<Edge> edges;
    vector<int> G[maxn];
    bool used[maxn];
    LL d[maxn];
    int p[maxn];

    void init(int n){
        this->n = n;
        for(int i=0;i<=n;++i)    G[i].clear();
        edges.clear();
        memset(used,0,sizeof(used));
    }

    void Addedge(int from,int to ,LL dist){
        edges.push_back((Edge){from,to,dist});
        m = edges.size();
        G[from].push_back(m-1);
    }

    void dijkstra(int s){   
        priority_queue<HeapNode> Q;
        for(int i=0;i<=n;++i)    d[i]=INF;
        d[s]=0;
        Q.push((HeapNode){0,s});
        while(!Q.empty()){
            HeapNode x =Q.top();Q.pop();
            int u =x.u;
            if(used[u]) 
                continue;
            used[u]= true;
            for(int i=0;i<G[u].size();++i){
                Edge & e = edges[G[u][i]];
                if(d[e.to] > d[u] + e.val){
                    d[e.to] = d[u] +e.val;
                    p[e.to] = G[u][i];
                    Q.push((HeapNode){d[e.to],e.to});
                }
            }
        }
    }
}Dijk;
const int MAXN=1010;
const int MAXM=200010;
struct Node{
    int from,to,next;
    int cap;
};
struct SAP_MaxFlow{
    int n,m;        
    int tol;
    int head[MAXN];
    int dep[MAXN];
    int gap[MAXN];
    Node edge[MAXM];

    void init(int N){
        this->n = N;
        this->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 SAP(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;
    }
}sap;
int n,m,s,t;
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		Dijk.init(n);
		sap.init(n);
		for(int i = 0;i<m;++i){
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			Dijk.Addedge(u,v,w);
		}
		scanf("%d%d",&s,&t);
		Dijk.dijkstra(s);
		for(int i = 0;i<m;++i){
			Edge e=Dijk.edges[i];
			if(Dijk.d[e.from]+e.val==Dijk.d[e.to]){
				sap.AddEdge(e.from,e.to,1);
			}
		} 
		printf("%d\n",sap.SAP(s,t));
	}
	return 0;
} 

 

上一篇:雅可比(Jacobi)迭代法解线性方程组的Matlab实现


下一篇:ACM菜鸡选手自备的模板(不喜勿喷,纯属自备