标签:注意 dir tom locking mem 新建 review turn 原来
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 **/
[最短路,最大流最小割定理] 2019 Multi-University Training Contest 1 Path
标签:注意 dir tom locking mem 新建 review turn 原来
原文地址:https://www.cnblogs.com/Railgun000/p/11408406.html