•题意
有n个城市,标号1-n
现花费最小的代价堵路
使得从1号城市到n号城市的路径边长
(注意只是变长不是最长)
堵一条路的代价是这条路的权值
•思路
在堵路以前,从1到n的最小路径当然是最短路
想要路径边长就要在最短路上动手脚
把从1到n的最短路找出来形成一个最短路图,
然后用最小的代价使得最短路图不连通
也就是求这个最短路图的最小割
那怎么建这个最短路图呢?
分别以1和n为源点跑一遍dijkstra,找出每个点到1和n的最短路
设$dis[1][i]$为1到i的最短路,$dis[n][i]$为i到n的最短路
$1->u->v->n$是$1->n$的一条最短路即$dis[1][u]+w[u->v]+dis[n][v]=dis[1][n]$
那么,u->v是1->n最短路上的一条边,加入最短路图中
(由于代码被某人嫌弃太乱,所以对dijkstra和dinic封装了一下...)
•代码
(未封装版)
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mem(a,b) memset(a,b,sizeof(a)) 4 #define ll long long 5 #define INF 0x3f3f3f3f3f3f3f3f 6 #define P pair<long long,int> 7 const int maxn=1e5+5; 8 int n,m; 9 struct Edge 10 { 11 int v; 12 ll w; 13 int next; 14 }de[maxn],fe[maxn],e[maxn]; 15 16 int head1[maxn],head2[maxn]; 17 int cnt1,cnt2; 18 void add(int u,int v,ll w) 19 { 20 de[++cnt1]={v,w,head1[u]}; 21 head1[u]=cnt1; 22 23 fe[++cnt2]={u,w,head2[v]}; 24 head2[v]=cnt2; 25 } 26 27 ll dis1[maxn],disn[maxn]; 28 bool vis1[maxn],visn[maxn]; 29 priority_queue<P,vector<P>,greater<P> >pq; 30 31 void dijkstra() 32 { 33 while(!pq.empty()) 34 pq.pop(); 35 for(int i=1;i<=n;i++) 36 dis1[i]=INF,vis1[i]=0; 37 dis1[1]=0; 38 pq.push(make_pair(0,1)); 39 while(!pq.empty()) 40 { 41 int u=pq.top().second; 42 pq.pop(); 43 if(!vis1[u]) 44 { 45 vis1[u]=1; 46 for(int i=head1[u];~i;i=de[i].next) 47 { 48 int v=de[i].v; 49 dis1[v]=min(dis1[v],dis1[u]+de[i].w); 50 pq.push(make_pair(dis1[v],v)); 51 } 52 } 53 } 54 55 while(!pq.empty()) 56 pq.pop(); 57 for(int i=1;i<=n;i++) 58 disn[i]=INF,visn[i]=0; 59 disn[n]=0; 60 61 pq.push(make_pair(0,n)); 62 while(!pq.empty()) 63 { 64 int u=pq.top().second; 65 pq.pop(); 66 if(!visn[u]) 67 { 68 visn[u]=1; 69 for(int i=head2[u];~i;i=fe[i].next) 70 { 71 int v=fe[i].v; 72 disn[v]=min(disn[v],disn[u]+fe[i].w); 73 pq.push(make_pair(disn[v],v)); 74 } 75 } 76 } 77 } 78 79 int head[maxn],cnt; 80 int cur[maxn],d[maxn]; 81 void addEdge(int u,int v,ll w) 82 { 83 e[++cnt]={v,w,head[u]}; 84 head[u]=cnt; 85 86 e[++cnt]={u,0,head[v]}; 87 head[v]=cnt; 88 } 89 90 bool bfs() 91 { 92 queue<int> q; 93 for(int i=1;i<=n;i++) 94 d[i]=-1; 95 d[1]=0; 96 q.push(1); 97 while(!q.empty()) 98 { 99 int u=q.front(); 100 q.pop(); 101 for(int i=head[u];~i;i=e[i].next) 102 { 103 int v=e[i].v; 104 if(d[v]==-1&&e[i].w>0) 105 { 106 d[v]=d[u]+1; 107 q.push(v); 108 } 109 } 110 } 111 return d[n]!=-1; 112 } 113 114 ll dfs(int u,ll flow) 115 { 116 ll nowflow=0; 117 if(u==n) return flow; 118 for(int i=cur[u];~i;i=e[i].next) 119 { 120 cur[u]=i; 121 int v=e[i].v; 122 if(d[v]==d[u]+1&&e[i].w>0) 123 { 124 ll k=dfs(v,min(flow-nowflow,e[i].w)); 125 if(k) 126 { 127 nowflow+=k; 128 e[i].w-=k; 129 e[i^1].w+=k; 130 if(nowflow==flow) 131 break; 132 } 133 } 134 } 135 if(!nowflow) d[u]=-2; 136 return nowflow; 137 } 138 139 ll Dinic() 140 { 141 ll ans=0; 142 while(bfs()) 143 { 144 for(int i=1;i<=n;i++) 145 cur[i]=head[i]; 146 147 ans+=dfs(1,INF); 148 } 149 return ans; 150 } 151 152 153 154 void Init() 155 { 156 mem(head1,-1); 157 mem(head2,-1); 158 mem(head,-1); 159 cnt1=cnt2=cnt=-1; 160 } 161 162 int main() 163 { 164 // freopen("C:\\Users\\14685\\Desktop\\C++workspace\\in&out\\contest","r",stdin); 165 int T; 166 scanf("%d",&T); 167 while(T--) 168 { 169 scanf("%d%d",&n,&m); 170 Init(); 171 for(int i=1;i<=m;i++) 172 { 173 int u,v; 174 ll w; 175 scanf("%d%d%lld",&u,&v,&w); 176 add(u,v,w); 177 } 178 179 dijkstra(); 180 181 for(int u=1;u<=n;u++) 182 { 183 for(int i=head1[u];~i;i=de[i].next) 184 { 185 int v=de[i].v; 186 if(dis1[u]+disn[v]+de[i].w==dis1[n]) 187 { 188 // printf("***%d %d %d\n",u,v,de[i].w); 189 addEdge(u,v,de[i].w); 190 } 191 } 192 } 193 194 printf("%lld\n",Dinic()); 195 } 196 }