HDU 5294 多校第一场1007题 最短路+最小割

                    Tricks Device

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1285    Accepted Submission(s): 302


Problem Description
Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu’s at the entrance of the tomb while Dumb Zhang’s at the end of it. The tomb is made up of many chambers, the total number is N. And there are M channels connecting the chambers. Innocent Wu wants to catch up Dumb Zhang to find out the answers of some questions, however, it’s Dumb Zhang’s intention to keep Innocent Wu in the dark, to do which he has to stop Innocent Wu from getting him. Only via the original shortest ways from the entrance to the end of the tomb costs the minimum time, and that’s the only chance Innocent Wu can catch Dumb Zhang.
Unfortunately, Dumb Zhang masters the art of becoming invisible(奇门遁甲) and tricks devices of this tomb, he can cut off the connections between chambers by using them. Dumb Zhang wanders how many channels at least he has to cut to stop Innocent Wu. And Innocent Wu wants to know after how many channels at most Dumb Zhang cut off Innocent Wu still has the chance to catch Dumb Zhang.
 
Input
There are multiple test cases. Please process till EOF.
For each case,the first line must includes two integers, N(<=2000), M(<=60000). N is the total number of the chambers, M is the total number of the channels.
In the following M lines, every line must includes three numbers, and use ai、bi、li as channel i connecting chamber ai and bi(1<=ai,bi<=n), it costs li(0<li<=100) minute to pass channel i.
The entrance of the tomb is at the chamber one, the end of tomb is at the chamber N.
 
Output
Output two numbers to stand for the answers of Dumb Zhang and Innocent Wu’s questions.
 
Sample Input
8 9
1 2 2
2 3 2
2 4 1
3 5 3
4 5 4
5 8 1
1 6 2
6 7 5
7 8 1
 
Sample Output
2 6
 
Author
FZUACM
 
Source
 
 
题意:
吴天真和张起灵分别在一个墓地的入口和出口
吴天真准备到出口找张起灵
已知这个墓地有N个房间,入口编号为1,出口编号为N,这N个房间有M条隧道连接
给出吴天真经过每一个隧道需要的时间
设吴天真从入口到达出口的最短时间为T
则张只会在出口处逗留T的时间,超过这个时间张就会离开,天真就再也找不到他了
由于张不希望被天真找到,所以张会施展他的奇门遁甲:
张可以指定若干隧道,被指定的隧道将会消失。
 
现在问题来啦:
张问你:他最少需要指定多少条隧道,才可以保证天真找不到他
天真也要问你:在保证天真可以找得到张的情况下, 张最多可以指定多少条隧道消失。
 
分析:
由于天真从1到达N所走的路径必须是最短路径,所以若一条路径不是最短路径,就不用管它了。
从1到N的最短路径不止一条,那么天真的问题等价为:
天真走那条隧道数最少的最短路径,若有x条边,则第二问的答案为总隧道数-x
如果对这个图重新建立,只保留所有的最短路径的边,则张的问题等价为:
求出这个新图的最小割。
 
而我们知道,一个图的最小割就等于最大流,所以求最大流就可以了。
而他要求的是最小割的边的总数啊?
只要我们建立新图的时候,把边的容量初始化为1,那么最后求得的最大流=最小割=最小割的边数
 
不过,我又有一个想法,如果先用dinic求出最大流,在level[T]<0的时候,对这个图的每一个节点,若level[i]>=0
则i是在集合S,若level[i]<0,则i是在集合T
然后遍历每一条边,如果边的起点在S,终点在T,则边数++
遍历完成后,边数就是割的边数了。
不过这样wa了,这个想法可以?我再去想想。
 
 
所以算法流程为:
1.保证天真走的是最短路的条件下,从1到达N的最少隧道数。
2.只保留所有的最短路径的边,建立新图
3.求出这个图的最大流
 
这道题我遇见了几个很好的情况,也说说:
1.以前做的题只要求出最短路的长度就可以了,这个要求的是最短路中边数最少的那一条路径的边数
做法:
加一个cnt数组,cnt[i]表示节点i到起点的最短路的最少边数
cnt[起点]=0,cnt[其他]=INF
然后spfa的同时更新cnt的值就好了
 
2.找出1到N所有的最短路径的边,建立新图
做法:
在求出起点到所有点的最短路径dis后,
遍历每一条边e,若dis[e.to]==dis[e.from]+e.cost
则边e是起点1到达点e.to的其中一条最短路径的边,加入,容量这道题是1
因为这条边有可能就是起点1到终点N的其中一条最短路径的边
 
3.求最小割的边数
做法:
当所有边的容量都是1的时候,最小割的边数=最小割=最大流
 
 
 
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<queue>
  5 #include<vector>
  6 
  7 using namespace std;
  8 
  9 const int  MAXN=2010;
 10 const int INF=0x3f3f3f3f;
 11 
 12 struct Edge1
 13 {
 14     int to,cost;
 15 };
 16 struct Edge2
 17 {
 18     int to,cap,rev;
 19 };
 20 
 21 vector<Edge1>edge1[MAXN];
 22 vector<Edge2>edge2[MAXN];
 23 
 24 void addedge1(int from,int to,int cost)
 25 {
 26     edge1[from].push_back((Edge1){to,cost});
 27     edge1[to].push_back((Edge1){from,cost});
 28 }
 29 void addedge2(int from,int to,int cap)
 30 {
 31     edge2[from].push_back((Edge2){to,cap,edge2[to].size()});
 32     edge2[to].push_back((Edge2){from,0,edge2[from].size()-1});
 33 }
 34 
 35 int iter[MAXN];
 36 int level[MAXN];
 37 int in[MAXN];   //求割的时候
 38 int vis[MAXN];
 39 int dis[MAXN];
 40 int cnt[MAXN];
 41 
 42 void init(int N)
 43 {
 44     for(int i=0;i<=N;i++)
 45     {
 46         edge1[i].clear();
 47         edge2[i].clear();
 48     }
 49 }
 50 
 51 void spfa(int N)
 52 {
 53     for(int i=1;i<=N;i++)
 54     {
 55         dis[i]=INF;
 56         cnt[i]=INF;
 57     }
 58     memset(vis,false,sizeof(vis));
 59 
 60     queue<int>que;
 61     while(!que.empty())
 62         que.pop();
 63 
 64     int str=1;
 65     que.push(str);
 66     vis[str]=true;
 67     dis[str]=0;
 68     cnt[str]=0;
 69 
 70     while(!que.empty())
 71     {
 72         int u=que.front();
 73         que.pop();
 74         vis[u]=false;   //重要
 75         for(int i=0;i<edge1[u].size();i++)
 76         {
 77             Edge1 &e=edge1[u][i];
 78             if(dis[e.to]==dis[u]+e.cost)
 79                 cnt[e.to]=min(cnt[e.to],cnt[u]+1);
 80             if(dis[e.to]>dis[u]+e.cost)
 81             {
 82                 dis[e.to]=dis[u]+e.cost;
 83                 cnt[e.to]=cnt[u]+1;
 84                 if(!vis[e.to])
 85                 {
 86                     vis[e.to]=true;
 87                     que.push(e.to);
 88                 }
 89             }
 90         }
 91     }
 92     return ;
 93 }
 94 
 95 void build_group(int N)
 96 {
 97     for(int i=1;i<=N;i++)
 98     {
 99         for(int j=0;j<edge1[i].size();j++)
100         {
101             Edge1 &e=edge1[i][j];
102             if(dis[e.to]==dis[i]+e.cost)
103                 addedge2(i,e.to,1);
104         }
105     }
106 }
107 
108 void bfs()
109 {
110     memset(level,-1,sizeof(level));
111     queue<int>que2;
112     while(!que2.empty())
113         que2.pop();
114     int s=1;
115     que2.push(s);
116     level[1]=0;
117     while(!que2.empty())
118     {
119         int u=que2.front();
120         que2.pop();
121         for(int i=0;i<edge2[u].size();i++)
122         {
123             Edge2 &e=edge2[u][i];
124             if(e.cap>0&&level[e.to]<0)
125             {
126                 level[e.to]=level[u]+1;
127                 que2.push(e.to);
128             }
129         }
130     }
131 }
132 
133 int dfs(int u,int T,int f)
134 {
135     if(u==T)
136         return f;
137     for(int &i=iter[u];i<edge2[u].size();i++)
138     {
139         Edge2 &e=edge2[u][i];
140         if(e.cap>0&&level[e.to]>level[u])
141         {
142             int d=dfs(e.to,T,min(e.cap,f));
143             if(d>0)
144             {
145                 e.cap-=d;
146                 edge2[e.to][e.rev].cap+=d;
147                 return d;
148             }
149         }
150     }
151     return 0;
152 }
153 
154 /*
155 int solve(int N)
156 {
157     for(int i=1;i<=N;i++)
158         in[i]=false;
159     for(int i=1;i<=N;i++)
160     {
161         if(level[i]>=0)
162             in[i]=true;
163     }
164 
165     int res=0;
166 
167     for(int i=1;i<=N;i++)
168     {
169         if(!in[i])
170             continue;
171         for(int j=0;j<edge2[i].size();j++)
172         {
173             Edge2 &e=edge2[i][j];
174             if(!in[e.to])
175                 res++;
176         }
177     }
178     return res;
179 }
180 */
181 
182 int max_flow(int N)
183 {
184     int flow=0;
185     while(1)
186     {
187         bfs();
188         if(level[N]<0)
189             break;
190         memset(iter,0,sizeof(iter));
191         int f;
192         while(f=dfs(1,N,INF))
193         {
194             flow+=f;
195         }
196     }
197     //return solve(N);
198     return flow;
199 }
200 
201 int main()
202 {
203     int N,M;
204     while(~scanf("%d%d",&N,&M))
205     {
206         init(N);
207 
208         for(int i=1;i<=M;i++)
209         {
210             int from,to,cost;
211             scanf("%d%d%d",&from,&to,&cost);
212             addedge1(from,to,cost);
213         }
214 
215         spfa(N);
216 
217         build_group(N);
218 
219         int cut=max_flow(N);
220 
221         printf("%d %d
",cut,M-cnt[N]);
222     }
223     return 0;
224 }
View Code
 
 
 
 
 
 
 
 
 
 
 
 

 

原文地址:https://www.cnblogs.com/-maybe/p/4668441.html