传送门

•题意

有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封装了一下...)

•代码

(未封装版)

  1 #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 }
View Code

相关文章: