2019暑假杭电训练赛(补题及笔记)

第一场

 

1005.Path

多年后,杰瑞爱上了一个女孩,他经常走很长时间去看望她。但是,因为他花太多的时间和他的女朋友在一起,汤姆觉得被忽视了,想阻止他去看她。经过对小区的研究,Tom发现小区正好由n栋房屋组成,其中一些房屋与直路相连。去看望他的女朋友,杰瑞需要从他的房子1开始,沿着最短路径,到达n。现在汤姆想要阻碍一些道路,使杰瑞走更长的时间到达女孩的家中,他发现阻塞道路的成本等于它的长度。现在他想知道使杰里走得更长所需的最低总成本。注意,如果Jerry一开始不能到他女朋友家,答案显然是零。而且你不需要保证在堵住了一些边之后,仍然有一条路从杰里的家到他女朋友的家。

Q:用最短的花费使最短路径变成。

A:实际上就是要找到所有可能的最短路径,然后做最小割。首先,求出最短路径,然后遍历边集,找到所有 Dis[v]== Dis[u]+ cost的边,构建一个图G'(用于求最大流的图,记得建回退边)。然后跑最大流得到结果(一个图的最小割等于这个图的最大流)。【代码:侯曜辉】

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<queue>
  6 using namespace std;
  7 typedef long long LL;
  8 const int maxv= 10010;
  9 const int maxe= 40010;
 10 const LL inf= 0x3f3f3f3f3f3f3f3f;
 11 
 12 struct ENode
 13 {
 14     int from;
 15     int to;
 16     LL w;
 17     int Next;
 18 };
 19 ENode edegs[maxe];
 20 int Head[maxv], tnt;
 21 void init()
 22 {
 23     memset(Head, -1, sizeof(Head));
 24     tnt= -1;
 25 }
 26 void Add_ENode(int a, int b, LL w)
 27 {
 28     ++ tnt;
 29     edegs[tnt].from= a;
 30     edegs[tnt].to= b;
 31     edegs[tnt].w= w;
 32     edegs[tnt].Next= Head[a];
 33     Head[a]= tnt;
 34 }
 35 
 36 LL dis[maxv];
 37 struct cmpx
 38 {
 39     bool operator() (int &a, int &b) const
 40     {
 41         return dis[a]- dis[b]> 0;
 42     }
 43 };
 44 void Dijkstra(int x)
 45 {
 46     priority_queue<int, vector<int>, cmpx> q;
 47     memset(dis, inf, sizeof(dis));
 48     dis[x]= 0;
 49     q.push(x);
 50 
 51     while (! q.empty())
 52     {
 53         int u= q.top();
 54         q.pop();
 55 
 56         for (int k= Head[u]; k!= -1; k= edegs[k].Next)
 57         {
 58             int v=  edegs[k].to;
 59             if (dis[v]> dis[u]+ edegs[k].w )
 60             {
 61                 dis[v]= dis[u]+ edegs[k].w;
 62                 q.push(v);
 63             }
 64         }
 65     }
 66 }
 67 
 68 /*建新图,跑最大流*/
 69 ENode edegs1[maxe];
 70 int Head1[maxv], tnt1;
 71 void init1()
 72 {
 73     memset(Head1, -1, sizeof(Head1));
 74     tnt1= -1;
 75 }
 76 void Add_ENode1(int a, int b,LL w)
 77 {
 78     ++ tnt1;
 79     edegs1[tnt1].from= a;
 80     edegs1[tnt1].to= b;
 81     edegs1[tnt1].w= w;
 82     edegs1[tnt1].Next= Head1[a];
 83     Head1[a]= tnt1;
 84     ++ tnt1;
 85     edegs1[tnt1].from= b;
 86     edegs1[tnt1].to= a;
 87     edegs1[tnt1].w= 0;
 88     edegs1[tnt1].Next= Head1[b];
 89     Head1[b]= tnt1;
 90 }
 91 void Dijk2(int n)
 92 {
 93     init1();
 94     for (int u= 1; u<= n; u ++)
 95     {
 96         for (int k= Head[u]; k!= -1; k= edegs[k].Next)
 97         {
 98             int v=  edegs[k].to;
 99             if (dis[v]== dis[u]+ edegs[k].w )
100             {
101                 Add_ENode1(u, v, edegs[k].w);
102             }
103         }
104     }
105 }
106 int level[maxv];
107 bool bfs_level (int s, int t)
108 {
109     memset(level, -1, sizeof(level)); //所有点的等级初始化为-1;
110     level[s]= 1; //源点的等级为1;
111     int que[maxv];  //队列que:按序保存已搜索到的点;
112     int iq= 0;
113     que[iq ++]= s; //先将源点s 加入队列;
114     for (int i= 0; i< iq; i ++)
115     {
116         int u= que[i];  //取出队首元素;
117         if (u== t)
118         {
119             /*找到汇点t,返回*/
120             return true;
121         }
122         for (int k= Head1[u]; k!= -1; k= edegs1[k].Next)
123         {
124             /*遍历,查找到之前未找到的、可抵达的点便加入队列*/
125             int v= edegs1[k].to;
126             if (-1== level[v]&& edegs1[k].w)
127             {
128                 level[v]= level[u]+ 1; //深度 +1;
129                 que[iq ++]= v;
130             }
131         }
132     }
133     return false;
134 }
135 LL dfs(int now, LL c_max, int t)
136 {
137     /**DFS 实现多路增广*/
138     /*now:起点;c_max:从源点s到节点now的最大流量;t:汇点、dfs结束的终点*/
139     if (now== t) return c_max; //当now== t时,c_max便是要求的最大流;
140     LL ret= 0, f;
141     for (int k= Head1[now]; k!= -1; k= edegs1[k].Next)
142     {
143         if (edegs1[k].w&& level[edegs1[k] .to]== level[now]+ 1)
144         {
145             /**/
146             f= dfs(edegs1[k].to, min(c_max- ret, edegs1[k].w), t);
147             edegs1[k].w-= f;
148             edegs1[k^1].w+= f;
149             ret+= f;
150             if(ret== c_max) return ret;
151         }
152     }
153     return ret;
154 }
155 LL dinic(int s, int t)
156 {
157     LL ans= 0;
158     while(bfs_level(s, t))
159     {
160         ans+= dfs(s, inf, t);
161     }
162     return ans;
163 }
164 
165 int main()
166 {
167     int t;
168     int n, m;
169     scanf("%d", &t);
170     while (t --)
171     {
172         scanf("%d %d", &n, &m);
173         init();
174         int a, b;
175         LL w;
176         for (int i= 0; i< m; i ++)
177         {
178             scanf("%d %d %lld", &a, &b, &w);
179             Add_ENode(a, b, w);
180         }
181         int start= 1, endd= n;
182 //        scanf("%d %d", &start, &endd);
183         Dijkstra(start);
184         LL ans;
185         if (dis[n]== inf) ans= 0;
186         else
187         {
188             Dijk2(n);
189 //        cout << dis[n] << " " << tnt1 << endl;
190 //        for (int i= 0; i<= tnt1; i ++)
191 //        {
192 //            cout << edegs1[i].from << "--->" << edegs1[i].to << "--->" << edegs1[i].w << endl;
193 //        }
194             ans= dinic(start, endd);
195         }
196 
197         printf("%lld\n", ans);
198     }
199     return 0;
200 }
View Code

 

1002.

转载于:https://www.cnblogs.com/Amaris-diana/p/11228766.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值