[最短路,最大流最小割定理] 2019 Multi-University Training Contest 1 Path

题目:http://acm.hdu.edu.cn/showproblem.php?pid=6582

Path

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 3747    Accepted Submission(s): 1075


Problem Description
Years later, Jerry fell in love with a girl, and he often walks for a long time to pay visits to her. But, because he spends too much time with his girlfriend, Tom feels neglected and wants to prevent him from visiting her.
After doing some research on the neighbourhood, Tom found that the neighbourhood consists of exactly  n houses, and some of them are connected with directed road. To visit his girlfriend, Jerry needs to start from his house indexed 1 and go along the shortest path to hers, indexed n
Now Tom wants to block some of the roads so that Jerry has to walk longer to reach his girl's home, and he found that the cost of blocking a road equals to its length. Now he wants to know the minimum total cost to make Jerry walk longer.
Note, if Jerry can't reach his girl's house in the very beginning, the answer is obviously zero. And you don't need to guarantee that there still exists a way from Jerry's house to his girl's after blocking some edges.
 

 

Input
The input begins with a line containing one integer  T(1T10), the number of test cases.
Each test case starts with a line containing two numbers n,m(1n,m10000), the number of houses and the number of one-way roads in the neighbourhood.
m lines follow, each of which consists of three integers x,y,c(1x,yn,1c109), denoting that there exists a one-way road from the house indexed x to y of length c.
 

 

Output
Print  T lines, each line containing a integer, the answer.
 

 

Sample Input
1 3 4 1 2 1 2 3 1 1 3 2 1 3 3
 

 

Sample Output
3
 

 

Source
 

 

Recommend
We have carefully selected several similar problems for you:   6718  6717  6716  6715  6714 

题意:

给n个节点m条有向边,现在可以删去一些边,代价为边权,问最小代价删去一些边使得现在节点1到节点n的最短路不成立(如果1不可达n则答案为0)

思路:

可能有多条1到n的最短路,这些最短路组成图,以最小代价使图不连通就是求最小割,由最大流最小割定理可知,最小割等于最大流,所以我们先找出图中1到n的最短路新建一个图,在这个图上从1到n跑一边最大流就可求出答案
现在就是建图的问题,我们先得到1到n的最短路径dis[i],再得到n到1的最短路径dis1[i],再把原图中符合dis[u]+e[i].w+dis1[v]==dis[n](令e[i].w为节点u到v的边权)的边建一个新图,
在这个新图上从1到n跑一边dinic就可得到答案

注意:

调了一个下午,在bool operator(const node &a)const{return a.w<w;}中原来是要a.w<w才能让优先队列中w小的优先,如果是a.w>w则是w大的优先

  1 #include<bits/stdc++.h>
  2 typedef long long ll;
  3 using namespace std;
  4 const int amn=1e4+5;
  5 const ll inf=1e18;
  6 struct edge{
  7     int from,to,nex;ll w;
  8 }eg[amn],eg1[amn],e[amn<<2|1];
  9 struct node{
 10     int p;
 11     ll w;
 12     node(int pp,ll ww){p=pp;w=ww;}
 13     bool operator<(const node &a)const{return a.w<w;}   ///调了一个下午,原来是要a.w<w才行,这样优先队列中才会w小的优先,如果是a.w>w则是w大的优先
 14 };
 15 ll head[amn],egn,head1[amn],egn1,n,m,dis[amn],dis1[amn],vis[amn],head2[amn],egn2;
 16 void init(int n){
 17     egn=0,egn1=0,egn2=1;    ///egn2是跑最大流的,初始为1,这样就可以从2开始加边,这样正向边和反向边相邻储存,因为2^1=3,3^1=2...所以可以异或得到正向边反向边
 18     for(int i=1;i<=n;i++)head2[i]=head1[i]=head[i]=0;
 19 }
 20 void add(int u,int v,ll w){     ///正向图加边
 21     eg[++egn].nex=head[u];
 22     head[u]=egn;
 23     eg[egn].from=u;
 24     eg[egn].to=v;
 25     eg[egn].w=w;
 26 }
 27 void add1(int u,int v,ll w){    ///反向图加边
 28         eg1[++egn1].nex=head1[u];
 29         head1[u]=egn1;
 30         eg1[egn1].from=u;
 31         eg1[egn1].to=v;
 32         eg1[egn1].w=w;
 33     }
 34 void add2(int u,int v,ll w){    ///跑最大流的新图加边
 35         e[++egn2].nex=head2[u];
 36         head2[u]=egn2;
 37         e[egn2].from=u;
 38         e[egn2].to=v;
 39         e[egn2].w=w;
 40     }
 41 
 42 ///以1为起点跑最短路
 43 void dijkstra(int s){
 44     memset(vis,0,sizeof vis);
 45     for(int i=0;i<=n;i++)dis[i]=inf;
 46     dis[s]=0;
 47     priority_queue<node> q;
 48     q.push(node(s,dis[s]));
 49     while(q.size()){
 50         int u=q.top().p;
 51         ll w=q.top().w;q.pop();
 52         if(w>dis[u])continue;
 53         vis[u]=1;
 54         for(int i=head[u];i;i=eg[i].nex){
 55             int v=eg[i].to;
 56             if(!vis[v]&&((dis[v])>(eg[i].w)+(dis[u]))){
 57                 dis[v]=(eg[i].w)+dis[u];
 58                 q.push(node(v,(dis[v])));
 59             }
 60         }
 61     }
 62 }
 63 ///以n为起点跑最短路
 64 void dijkstra1(int s){
 65     memset(vis,0,sizeof vis);
 66     for(int i=0;i<=n;i++)dis1[i]=inf;
 67     dis1[s]=0;
 68     priority_queue<node> q;
 69     q.push(node(s,dis1[s]));
 70     while(q.size()){
 71         int u=q.top().p;
 72         ll w=q.top().w;q.pop();
 73         if(w>dis1[u])continue;
 74         vis[u]=1;
 75         for(int i=head1[u];i;i=eg1[i].nex){
 76             int v=eg1[i].to;
 77             if(!vis[v]&&((dis1[v])>(eg1[i].w)+(dis1[u]))){
 78                 dis1[v]=(eg1[i].w)+dis1[u];
 79                 q.push(node(v,(dis1[v])));
 80             }
 81         }
 82     }
 83 }
 84 ///dinic最大流
 85 queue<int> que;
 86 ll dist[amn],src=1,sink=n;
 87 void bfs(){
 88     memset(dist,0,sizeof dist);
 89     while(que.size())que.pop();
 90     vis[src]=1;
 91     que.push(src);
 92     while(que.size()){
 93         int u=que.front();que.pop();
 94         for(int i=head2[u];i;i=e[i].nex){
 95             int v=e[i].to;//cout<<'>'<<e[i].w<<' '<<v<<endl;
 96             if(e[i].w&&!vis[v]){
 97                 que.push(v);
 98                 dist[v]=dist[u]+1;
 99                 vis[v]=1;
100             }
101         }
102     }
103 }
104 int dfs(int u,ll delta){
105     if(u==sink)return delta;
106     int ret=0;
107     for(int i=head2[u];delta&&i;i=e[i].nex)
108     if(e[i].w&&(dist[e[i].to]==dist[u]+1)){
109         ll dd=dfs(e[i].to,min(e[i].w,delta));
110         e[i].w-=dd;
111         e[i^1].w+=dd;
112         delta-=dd;
113         ret+=dd;
114     }
115     return ret;
116 }
117 ll maxflow(){
118     ll ret=0;
119     while(1){
120         memset(vis,0,sizeof vis);
121         bfs();
122         if(!vis[sink])return ret;//cout<<'<'<<ret<<endl;
123         ret+=dfs(src,inf);
124     }
125 }
126 int main(){
127     int T,x,y;ll c;
128     scanf("%d",&T);
129     while(T--){
130         scanf("%lld%lld",&n,&m);
131         init(n);            ///初始化
132         src=1,sink=n;       ///设置1为源点,n为汇点
133         for(int i=1;i<=m;i++){
134             scanf("%d%d%lld",&x,&y,&c);
135             add(x,y,c);     ///正向图,为了以1为起点跑最短路
136             add1(y,x,c);    ///反向图,为了以n为起点跑最短路
137         }
138         dijkstra(1);        ///以1为起点的最短路
139         if(dis[n]==inf){printf("0\n");continue;}    ///如果1到n不可达则输出0
140         dijkstra1(n);       ///以n为起点的最短路
141         for(int i=1;i<=egn;i++){
142 //            cout<<eg[i].from<<' '<<eg[i].to<<' '<<eg[i].w<<endl;
143 //            cout<<dis[eg[i].from]<<' '<<eg[i].w<<' '<<dis1[eg[i].to]<<' '<<dis[n]<<endl<<endl;
144             if(dis[eg[i].from]+eg[i].w+dis1[eg[i].to]==dis[n]){     ///如果1到现在这个点u的最短路径+u到v的边权+v到n的最短路径==1到n的最短路径则u到v这条边是最短路中的一条边
145                 add2(eg[i].from,eg[i].to,eg[i].w);  ///建新图,加正向边
146                 add2(eg[i].to,eg[i].from,0);        ///边权为0的反向边
147             }
148         }
149         printf("%lld\n",maxflow());     ///最大流等于最小割
150     }
151 }
152 /**
153 给n个节点m条有向边,现在可以删去一些边,代价为边权,问最小代价删去一些边使得现在节点1到节点n的最短路不成立(如果1不可达n则答案为0)
154 可能有多条1到n的最短路,这些最短路组成图,以最小代价使图不连通就是求最小割,由最大流最小割定理可知,最小割等于最大流,所以我们先找出图中1到n的最短路新建一个图,在这个图上从1到n跑一边最大流就可求出答案
155 现在就是建图的问题,我们先得到1到n的最短路径dis[i],再得到n到1的最短路径dis1[i],再把原图中符合dis[u]+e[i].w+dis1[v]==dis[n](令e[i].w为节点u到v的边权)的边建一个新图,
156 在这个新图上从1到n跑一边dinic就可得到答案
157 调了一个下午,在bool operator(const node &a)const{return a.w<w;}中原来是要a.w<w才能让优先队列中w小的优先,如果是a.w>w则是w大的优先
158 **/

猜你喜欢

转载自www.cnblogs.com/Railgun000/p/11408406.html