HDU 3416 关于求一个图中最短路的条数问题(即最短路的唯一性) 网络最大流的具体应用

Marriage Match IV

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

题目大意:就是给你一个有向图,问你这个有向图从1号点到N号点的最短路径是否唯一,不唯一的话就输出有多少条这样的最短路存在,注意一个点可以走多次

要确定唯一性,暴力肯定是不过的,可以考虑一种更优的方法-----网络最大流,网络最大流就是一种从源点到汇点的最大值,保证了路径上的唯一性,那么就可以将属于最短路上的最短边加入到网络流当中里面去,这样在保证不重复走一条路径的同时还能够确定到汇点的最大值是多少(网络流的容量为1),我们首先要明白怎样去确定哪些是属于最短路径上的最短边,这里有一个方法是需要知道的:

dist1[a[i]]+dist2[b[i]]+c[i]==dist1[B];

dist1表示正向到达a[i]的最短路径,dist2表示反向到达b[i]的最短路径,c[i]表示从a[i]到b[i]的权值,如果是满足上式的点那就将a[i]-->b[i]这条边的权值设为1建成网络流,那么剩下的就是套最短路还有IPAF的模板了


#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int MAXN=2010;
const int MAXM=2000010;
const int INF=0x3f3f3f3f;

//最大流SAP

struct Node
{
    int to,next,cap,flow;
}edge[MAXM];
int tol;
int head[MAXN];
int gap[MAXN],dis[MAXN],p[MAXN],cur[MAXN];
void init()
{
    tol=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw=0)//tol一定要从0开始,因为ISAP中的异或运算时0与1,2与3
//这样配对的
{
    edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=0;edge[tol].next=head[u];head[u]=tol++;
    edge[tol].to=u;edge[tol].cap=rw;edge[tol].flow=0;edge[tol].next=head[v];head[v]=tol++;
}
int d[MAXN];
int sap(int s,int t,int N){
  memset(gap, 0, sizeof(gap));
  memset(d, 0, sizeof(d));
  memcpy(cur, head, sizeof(head));
  int u=s;
  p[u]=-1;
  gap[0]=N;
  int ans=0;
  while(d[s]<N){
    if(u == t){
      int Min=INF;
      for(int i=p[u]; i!=-1; i=p[edge[i^1].to])//找最小残量值
        if(Min>edge[i].cap-edge[i].flow)
          Min=edge[i].cap-edge[i].flow;
      for(int i = p[u]; i!=-1; i=p[edge[i^1].to]){//增广
        edge[i].flow+=Min;
        edge[i^1].flow-=Min;
      }
      u=s;
      ans+=Min;
      continue;
    }
    bool ok=false;
    int v;
    for(int i=cur[u]; i!=-1; i=edge[i].next){
        v=edge[i].to;
        if(edge[i].cap-edge[i].flow && d[v]+1==d[u]){//Advance前进
          ok=true;
          cur[u]=p[v]=i;
          break;
        }
    }
    if(ok){
      u=v;
      continue;
    }
    //Retreat走不动了,撤退
    int Min=N;
    for(int i=head[u]; i!=-1; i=edge[i].next)
      if(edge[i].cap-edge[i].flow && d[edge[i].to] < Min){
        Min=d[edge[i].to];
        cur[u]=i;
      }
    gap[d[u]]--;
    if(!gap[d[u]])return ans;
    d[u] = Min+1;
    gap[d[u]]++;
    if(u!=s) u=edge[p[u]^1].to;//退一步,沿父边返回
  }
  return ans;
}




//SPFA
int first[MAXN];
bool vis[MAXN];
int cnt[MAXN];
int que[MAXN];
int dist[MAXN];
struct Edge
{
    int to,v,next;
}edge1[MAXM];
int tt;
void add(int a,int b,int v)
{
    edge1[tt].to=b;
    edge1[tt].v=v;
    edge1[tt].next=first[a];
    first[a]=tt++;
}
bool SPFA(int start,int n)
{
    int front=0,rear=0;
    for(int v=1;v<=n;v++)
    {
        if(v==start)
        {
            que[rear++]=v;
            vis[v]=true;
            cnt[v]=1;
            dist[v]=0;
        }
        else
        {
            vis[v]=false;
            cnt[v]=0;
            dist[v]=INF;
        }
    }
    while(front!=rear)
    {
        int u=que[front++];
        vis[u]=false;
        if(front>=MAXN)front=0;
        for(int i=first[u];i!=-1;i=edge1[i].next)
        {
            int v=edge1[i].to;
            if(dist[v]>dist[u]+edge1[i].v)
            {
                dist[v]=dist[u]+edge1[i].v;
                if(!vis[v])
                {
                    vis[v]=true;
                    que[rear++]=v;
                    if(rear>=MAXN)rear=0;
                    if(++cnt[v]>n)return false;
                }
            }
        }
    }
    return true;
}
int a[100010],b[100010],c[100010];
int dist1[MAXN],dist2[MAXN];
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    int n,m;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        int A,B;
        for(int i=0;i<m;i++)
            scanf("%d%d%d",&a[i],&b[i],&c[i]);
        scanf("%d%d",&A,&B);
        tt=0;
        memset(first,-1,sizeof(first));
        for(int i=0;i<m;i++)
            add(a[i],b[i],c[i]);yi
        SPFA(A,n);
        memcpy(dist1,dist,sizeof(dist));
        tt=0;
        memset(first,-1,sizeof(first));
        for(int i=0;i<m;i++)
            add(b[i],a[i],c[i]);
        SPFA(B,n);
        memcpy(dist2,dist,sizeof(dist));
        init();
        for(int i=0;i<m;i++)
        {
            if(a[i]!=b[i] && dist1[a[i]]+dist2[b[i]]+c[i]==dist1[B])
                addedge(a[i],b[i],1);
        }
        //cout<<tol<<endl;
        printf("%d\n",sap(A,B,n));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/c___c18/article/details/82289384