HDU 3416

//题目大意:求两点之间最短路的条数,但是前提是已走过的路径不能重复
//题目类型:最大流+最短路径
//解题思路:首先用Dijkstra求出两点之间的最短路,然后判断每条边是否在最短路上,如果在最短路上,则流量自增1 ,然后求出最大流
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdio>
//#include <conio.h>
using namespace std;
                                
const int narray = 1010;             
const int marray = 100010;
const int INF=0x7fffffff; 
struct edge_T
{
     int u;   //起点(为了最大流建图方便)
     int v;   //终点
     int w;
     edge_T *next;
}*adj[narray], edges[marray],*readj[narray],reedges[marray];     
bool final[marray];
struct node_T
{             
     int v;
     int len;
     bool operator < (const node_T &nod) const
     {
          return len > nod.len;
     }
};
int edgenum,reedgenum;              //记录边的总数
int vn,en;             //记录定点数和边数
int src,des;
int dista[narray],distb[narray];

void addEdge(int u, int v, int w)
{   
     edge_T *ptr = &edges[edgenum];
     ptr->u = u;
     ptr->v = v;
     ptr->w = w;
     ptr->next = adj[u];    //往前插入边
     adj[u] = ptr;
     edgenum++;
}
void addReedge(int u,int v,int w)
{
     edge_T *ptr = &reedges[reedgenum];
     ptr->u = u;
     ptr->v = v;
     ptr->w = w;
     ptr->next = readj[u];    //往前插入边
     readj[u] = ptr;
     reedgenum++;
}
int dijkstra(int s,int t,int dist[],int flag)
{      
     int i;    
     priority_queue <node_T> Q;            //使用优先级队列实现
     node_T cur;
     edge_T *ptr;
     cur.v = s;
     cur.len = 0;
     Q.push(cur);
     for(int i = 1; i <= vn; i ++)
     {
          dist[i] = INF;   
     }      
     dist[s] = 0;
     while(!Q.empty())
     {
          int v = Q.top().v;               //优先级队列使用top()
          int len = Q.top().len;
          Q.pop();
          if(dist[v]!=len) continue;
          if(flag == 1)  ptr = adj[v];
          else ptr = readj[v];
          for(; ptr; ptr = ptr -> next)
          {
               int u = ptr -> v;
               int w = ptr -> w;
               if(dist[v] + w < dist[u])
               {
                    dist[u] = dist[v] + w;
                    cur.v = u;
                    cur.len = dist[u];
                    Q.push(cur);                   
               }
          }
     }
     return dist[t];
}

int capacity[narray][narray];    
int pre[narray];                  
int num[narray];                    
int d[narray];                       

void init(int src,int des)             
{
     int i,j;
     queue<int> myqueue;
     myqueue.push(des);
     memset(num,0,sizeof(num));
     for(i=1;i<=vn;++i)     
        d[i] = INF;
     d[des] = 0;            
     num[0] = 1;
     int frontint;
     while(!myqueue.empty()) 
     {
         frontint = myqueue.front();myqueue.pop();
         for(i=1;i<=vn;++i)
         {
             if(d[i]>=vn && capacity[i][frontint]>0)  
             {
                 d[i] = d[frontint]+1;
                 myqueue.push(i); 
                 num[d[i]]++;    
             }                 
         }
     }
}
int findarc(int t)             
{
    int i,j;
    for(i=1;i<=vn;++i)
    {
        if(capacity[t][i]>0 && d[t]==d[i]+1) return i;
    }
    return -1;
}
int relabel(int t)             
{
    int i,j;
    int mm = INF;
    for(i=1;i<=vn;++i)
    {
        if(capacity[t][i]>0) mm = min(mm,d[i]+1);
    }
    return mm==INF?vn:mm;
}
int maxFlow(int src,int des)
{
    int sumflow = 0;
    int delta;
    int i=src;     
    int j;
    memset(pre,-1,sizeof(pre));   
    while(d[src]<vn)
    {
       j = findarc(i);
       if(j>=0)
       {
           pre[j] = i;
           i = j;          
           if(i==des)        
           {
               delta = INF;
               for (i=des;i!=src;i=pre[i]) delta=min(delta,capacity[pre[i]][i]);   
               for (i=des;i!=src;i=pre[i]) capacity[pre[i]][i] -= delta, capacity[i][pre[i]] += delta;
               sumflow += delta;
           }
       }
       else
       {
           int x = relabel(i);
           num[x]++;
           num[d[i]]--;
           if(num[d[i]]==0) return sumflow;    
           d[i] = x;
           if(i!=src) i =pre[i];          
       }
    }
    return sumflow;
}
//见图并求最大流
void buildAndMaxFlow(int res)
{
     int i,j;
     memset(capacity,0,sizeof(capacity));    
     for(i=1;i<edgenum;++i)       //遍历所有的边(此处使用edgenum,因为可能存在负权回路的情况)
     {
          int u = edges[i].u;
          int v = edges[i].v;
          int w = edges[i].w;
          if(dista[u]+distb[v]+w==res)     //如果边的起点到源点的距离+边的权值+边的终点到汇点的距离等于汇点到源点的距离   
          {
              capacity[u][v]++;
          }
     }
     init(src,des);            //在求最大流之前首先初始化标顶
     printf("%d\n",maxFlow(src,des));
}
int main()
{
      //freopen("1.txt","r",stdin);
      int t;
      int i;
      int res;
      scanf("%d",&t);
      while(t--)
      {
          scanf("%d %d", &vn, &en);
          for(i = 1; i <= vn; i ++)
          {
               adj[i] = NULL;                //初始化邻接表的指针
               readj[i] = NULL;
          }
          edgenum = 1;                       //初始化边数
          reedgenum =1;
          int u, v;
          int w;
          for(i = 1; i <= en; i ++)
          {       
               scanf("%d%d%d", &u, &v, &w);
               if(u==v) continue;    //判断是否有环
               addEdge(u, v, w);
               addReedge(v,u,w);
          }
          scanf("%d%d",&src,&des);
          //分别求出途中各点到源点和终点之间的距离
          dijkstra(src,des,dista,1);
          res = dijkstra(des,src,distb,2);
          buildAndMaxFlow(res);
      }    
      //getch();
      return 0;
}

posted @ 2010-06-07 21:30  北海小龙  阅读(592)  评论(0编辑  收藏  举报