HDU 3416 最短路+最大流

Marriage Match IV

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1486    Accepted Submission(s): 416

 

Problem Description

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

题目大意:在满足最短路的前提下,并且每条路只能走一次,问能走几次最短路。

思路:分别用两次spfa,第一次求出各点离出发点A的最短路,存在数组lowA[]中;第二次求出各点离目的地B的最短路,存到数组lowB[]中(此时要注意,因为边是单向边,此次求spfa时,松弛时要注意,若输入边的时候存边用数组map[i][j]存,那么第二次spfa时应该将下标互换,详细可见代码;构图时,枚举所有边,如果该边的起点为a,终点为b,边长为c,则若满足lowA[a]+lowB[b]+c == lowA[B](B为目的地),也就是  该边的起点到出发点的最短距离+边的终点到目的地的最短距离+起点到终点的距离 == 出发点到目的地的最短距离 ,则将该边加入到网络图中。可自己在纸上画画便可知道。

代码写得很搓,留给自己反省反省。

View Code
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <queue>
  6 #include <algorithm>
  7 #define INF 100000005
  8 #define MAX 1005
  9 
 10 using namespace std;
 11 
 12 struct node
 13 {
 14     int to,val,next;
 15 };
 16 
 17 int T,N,M,A,B;
 18 
 19 int map[MAX][MAX];  //存路径的链接情况
 20 int st[MAX*105],ed[MAX*105],cost[MAX*105]; //存所有的边,从左到右分别是边的起点,终点,长度
 21 int lowA[MAX],lowB[MAX];  //存各点到A的最短路径,各点到B的最短路径
 22 bool inQueue[MAX]; 
 23 
 24 node edge[MAX * MAX];
 25 int head[MAX];
 26 int idx;
 27 
 28 int dis[MAX];
 29 int gap[MAX];
 30 
 31 void addNode(int from,int to,int val)
 32 {
 33     edge[idx].to = to;
 34     edge[idx].val = val;
 35     edge[idx].next = head[from];
 36     head[from] = idx ++;
 37     edge[idx].to = from;
 38     edge[idx].val = 0;
 39     edge[idx].next = head[to];
 40     head[to] = idx ++;
 41 }
 42 
 43 void spfa_A()
 44 {
 45     queue <int> Q;
 46     for(int i=1; i<MAX; i++)
 47     {
 48         lowA[i] = INF;
 49         inQueue[i] = false;
 50     }
 51     lowA[A] = 0;
 52     inQueue[A] = true;
 53     Q.push(A);
 54     while(!Q.empty())
 55     {
 56         int temp = Q.front();
 57         Q.pop();
 58         inQueue[temp] = false;
 59         for(int i=1; i<=N; i++)
 60         {
 61             if(lowA[i] > lowA[temp] + map[temp][i])
 62             {
 63                 lowA[i] = lowA[temp] + map[temp][i];
 64                 if(!inQueue[i])
 65                 {
 66                     Q.push(i);
 67                     inQueue[i] = true;
 68                 }
 69             }
 70         }
 71     }
 72 }
 73 
 74 void spfa_B()
 75 {
 76     queue <int> Q;
 77     for(int i=1; i<MAX; i++)
 78     {
 79         lowB[i] = INF;
 80         inQueue[i] = false;
 81     }
 82     lowB[B] = 0;
 83     inQueue[B] = true;
 84     Q.push(B);
 85     while(!Q.empty())
 86     {
 87         int temp = Q.front();
 88         Q.pop();
 89         inQueue[temp] = false;
 90         for(int i=1; i<=N; i++)
 91         {
 92             if(lowB[i] > lowB[temp] + map[i][temp]) //松弛时该注意单向边的影响,区别与spfa_A()
 93             {
 94                 lowB[i] = lowB[temp] + map[i][temp];
 95                 if(!inQueue[i])
 96                 {
 97                     Q.push(i);
 98                     inQueue[i] = true;
 99                 }
100             }
101         }
102     }
103 }
104 
105 //以下是ISAP求最大流
106 int dfs(int cur,int cur_val)  
107 {
108     if(cur == B)
109         return cur_val;
110     int min_dis = N-1, temp_val = cur_val;
111     for(int i=head[cur]; i!=-1; i=edge[i].next)
112     {
113         int to = edge[i].to, value = edge[i].val;
114         if(value > 0)
115         {
116             if(dis[to] + 1 == dis[cur])
117             {
118                 int val = min(temp_val,edge[i].val);
119                 val = dfs(to,val);
120                 temp_val -= val;
121                 edge[i].val -= val;
122                 edge[i^1].val += val;
123                 if(dis[A] >= N)
124                     return cur_val - temp_val;
125                 if(temp_val == 0)
126                     break;
127             }
128             if(dis[cur] < min_dis)
129                 min_dis = dis[cur];
130         }
131     }
132     if(cur_val == temp_val)
133     {
134         --gap[dis[cur]];
135         if(gap[dis[cur]] == 0)
136             dis[A] = N;
137         dis[cur] = min_dis + 1;
138         ++gap[dis[cur]];
139     }
140     return cur_val - temp_val;
141 }
142 
143 int sap()
144 {
145     memset(gap,0,sizeof(gap));
146     memset(dis,0,sizeof(dis));
147     int ret = 0;
148     gap[A] = N;
149     while(dis[A] < N)
150         ret += dfs(A,INF);
151     return ret;
152 }
153 
154 void init()
155 {
156     idx = 0;
157     for(int i=0; i<=N; i++)
158     {
159         head[i] = -1;
160         for(int j=0; j<=N; j++)
161         {
162             map[i][j] = INF;
163             if(i == j)
164                 map[i][j] = 0;
165         }
166     }
167 }
168 
169 int main()
170 {
171     scanf("%d",&T);
172     while(T--)
173     {
174         scanf("%d%d",&N,&M);
175         if(M == 0)
176         {
177             printf("0\n");
178             continue;
179         }
180         init();
181         for(int i=1; i<=M; i++)
182         {
183             scanf("%d%d%d",&st[i],&ed[i],&cost[i]);
184             map[st[i]][ed[i]] = min(map[st[i]][ed[i]],cost[i]);
185         }
186         scanf("%d%d",&A,&B);
187         spfa_A();
188         spfa_B();
189         for(int i=1; i<=M; i++)
190         {
191             if(st[i]!=ed[i] && lowA[st[i]]+lowB[ed[i]]+cost[i] == lowA[B])
192                 addNode(st[i],ed[i],1);
193         }
194         int ans = sap();
195         printf("%d\n",ans);
196     }
197     return 0;
198 }

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值