[最短路,最大流最小割定理] 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(1≤T≤10), the number of test cases.
Each test case starts with a line containing two numbers n,m(1≤n,m≤10000), 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(1≤x,y≤n,1≤c≤109), 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 2019 Multi-University Training Contest 1
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 **/
标签:dis1,Multi,amn,int,Contest,Training,vis,que,dis 来源: https://www.cnblogs.com/Railgun000/p/11408406.html