HDU 4411 Arrest 费用流 建边技巧
2014-09-08 23:24
351 查看
题意:有(N+1)个城市,M条路,每条路有距离。
在城市0有警察总局,里面有K个警察。从城市1到城市N,每个城市都有盗贼。我们要派出警察消灭这些盗贼。
警察到达一个城市可以选择抓捕盗贼或者不抓捕盗贼。且最后,所有的警察必须回到警察总局。
当第i个城市的盗贼被逮捕时,他们回向第i-1个城市发送警报,如果有盗贼收到警报,那这个行动就失败了。
求:在完成任务的情况下,最小化所有警察走过的距离。
思路:对于盗贼的警报,我们要从第一个城市开始,按顺序抓捕。
首先我们可以通floyd算法求出多源最短路。
接下来我们可以用最小费用流建图:
1.从源点s向城市0连容量为k,费用为0的边,表示至多可以使用k个警察。
2.从城市0向其他城市i,连容量为INF,费用为d[0][i]的边,表示从总局直接向该城市派警察。
3.城市i向汇点t连容量为INF,费用为d[0][i],表示警察直接从该城市回到总局。
4.城市0向汇点t连容量为K,费用为0的边,表示至多有K个警察可以不用出动,一直待在总局。
5.因为对于每个城市,我们必须要处理,且只能处理一次。在网络流中,对于至多访问一次的点,我们用拆点进行处理。而必须要处理的点,可以设其费用为-INF,由于是求最小费用,那该点一定会被处理到(否则就不是最小费用了)。所以,我们将城市i拆成入点:点i,出点:点i+N.从入点到出点连费用为-INF,容量为1的边。同时,2中的边要连向入点,3中的边要从出点连出。
6.这个题最难处理的其实是顺序访问。我们要对城市i的出点i+N,向位于他后面的城市j(i < j <= N)的入点连容量为INF,费用为的d[i][j]的边。这样我们可以保证是顺序访问了。
这样我们就可以跑出最小费用,然后加上N * INF,就是最终的答案。
几点小小的解释:
1.对于建边中2,3,6,条,边的容量可以为1。这是因为,如果多个警察派往一个城市,处理的盗贼不变,但总的距离多了,所以相比,最好的方案是让每个警察去抓不同的盗贼,完成不同的任务。
2.对于警察到达一个城市可以选择抓捕盗贼还是不抓的要求,是通过floyd算法求最短路实现的。因为最短路相当于从起点出发,在路上隐身,到终点抓盗贼。
3.对6的建边方法能够保证顺序访问:首先,如果多个警察出动,那我们可以单独安排每个警察的行动,从而保证抓捕顺序的先后。而对于一个警察,因为总是从排在前面的城市向排在后面的城市连边,也能保证抓捕顺序的先后。在建图时,我们对城市i,向他后面的所有城市连边,也保证了多个警察行动,对一个警察而言,会出现跳跃式的抓捕(因为其他的警察已经抓了)的情况。
代码如下:
在城市0有警察总局,里面有K个警察。从城市1到城市N,每个城市都有盗贼。我们要派出警察消灭这些盗贼。
警察到达一个城市可以选择抓捕盗贼或者不抓捕盗贼。且最后,所有的警察必须回到警察总局。
当第i个城市的盗贼被逮捕时,他们回向第i-1个城市发送警报,如果有盗贼收到警报,那这个行动就失败了。
求:在完成任务的情况下,最小化所有警察走过的距离。
思路:对于盗贼的警报,我们要从第一个城市开始,按顺序抓捕。
首先我们可以通floyd算法求出多源最短路。
接下来我们可以用最小费用流建图:
1.从源点s向城市0连容量为k,费用为0的边,表示至多可以使用k个警察。
2.从城市0向其他城市i,连容量为INF,费用为d[0][i]的边,表示从总局直接向该城市派警察。
3.城市i向汇点t连容量为INF,费用为d[0][i],表示警察直接从该城市回到总局。
4.城市0向汇点t连容量为K,费用为0的边,表示至多有K个警察可以不用出动,一直待在总局。
5.因为对于每个城市,我们必须要处理,且只能处理一次。在网络流中,对于至多访问一次的点,我们用拆点进行处理。而必须要处理的点,可以设其费用为-INF,由于是求最小费用,那该点一定会被处理到(否则就不是最小费用了)。所以,我们将城市i拆成入点:点i,出点:点i+N.从入点到出点连费用为-INF,容量为1的边。同时,2中的边要连向入点,3中的边要从出点连出。
6.这个题最难处理的其实是顺序访问。我们要对城市i的出点i+N,向位于他后面的城市j(i < j <= N)的入点连容量为INF,费用为的d[i][j]的边。这样我们可以保证是顺序访问了。
这样我们就可以跑出最小费用,然后加上N * INF,就是最终的答案。
几点小小的解释:
1.对于建边中2,3,6,条,边的容量可以为1。这是因为,如果多个警察派往一个城市,处理的盗贼不变,但总的距离多了,所以相比,最好的方案是让每个警察去抓不同的盗贼,完成不同的任务。
2.对于警察到达一个城市可以选择抓捕盗贼还是不抓的要求,是通过floyd算法求最短路实现的。因为最短路相当于从起点出发,在路上隐身,到终点抓盗贼。
3.对6的建边方法能够保证顺序访问:首先,如果多个警察出动,那我们可以单独安排每个警察的行动,从而保证抓捕顺序的先后。而对于一个警察,因为总是从排在前面的城市向排在后面的城市连边,也能保证抓捕顺序的先后。在建图时,我们对城市i,向他后面的所有城市连边,也保证了多个警察行动,对一个警察而言,会出现跳跃式的抓捕(因为其他的警察已经抓了)的情况。
代码如下:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; struct edge{ int from,to,cap,flow,cost; edge(int u = 0,int v = 0, int c= 0,int f = 0, int w = 0): from(u),to(v),cap(c),flow(f),cost(w){} }; struct mcmf{ int n,m,s,t; static const int MAX = 20000; static const int INF = 0x3f3f3f3f; edge edges[MAX]; int head[MAX]; int next[MAX]; int tot; int que[MAX],front,tail; bool inq[MAX]; int d[MAX]; int p[MAX]; int a[MAX]; void init(){ memset(head,-1,sizeof(head)); tot = 0; } void addedge(int from, int to, int cap, int cost){ edges[tot] = edge(from,to,cap,0,cost); next[tot] = head[from],head[from] = tot++; edges[tot] = edge(to,from,0,0,-cost); next[tot] = head[to],head[to] = tot++; } bool bellmanford(int s, int t,int & flow, int &cost){ memset(d,0x3f,sizeof(d)); memset(inq,false,sizeof(inq)); d[s] = 0,inq[s] = true,p[s] = 0,a[s] = INF; front = tail = 0; que[tail++] = s; while(front < tail){ int u = que[front++];inq[u] = false; for(int v = head[u]; v != -1; v = next[v]){ edge & e = edges[v]; if(e.cap > e.flow && d[e.to] > d[u] + e.cost){ d[e.to] = d[u] + e.cost; p[e.to] = v; a[e.to] = min(a[u],e.cap - e.flow); if(!inq[e.to]) que[tail++] = e.to,inq[e.to] = true; } } } if(d[t] == INF) return false; flow += a[t]; cost += d[t]; for(int u = t; u != s; u = edges[p[u]].from){ //printf("%d ",u);; edges[p[u]].flow += a[t]; edges[p[u]^1].flow -=a[t]; } // printf("\n"); return true; } int mincost(int s,int t){ int flow = 0,cost = 0; while(bellmanford(s,t,flow,cost)); return cost; } } solver; const int MAX = 200; const int INF = 0x3f3f3f; int N,M,K; int d[MAX][MAX]; int x,y,t; void floyd() { for(int i = 0 ; i < N; ++i) d[i][i] = 0; for(int k = 0 ; k <= N;++k) for(int i = 0 ; i <= N; ++i) for(int j = 0 ; j <= N; ++j) d[i][j] = min(d[i][j],d[i][k] + d[k][j]); } int main(void) { //freopen("input.txt","r",stdin); while(scanf("%d %d %d", &N,&M,&K),N||M||K){ memset(d,0x3f,sizeof(d)); for(int i = 0; i < M; ++i){ scanf("%d %d %d", &x, &y, &t); d[x][y] = d[y][x] = min(t,d[x][y]); } floyd(); int s = 2 * N + 1, t = 2 * N + 2; solver.init(); solver.addedge(s,0,K,0); solver.addedge(0,t,K,0); for(int i = 1; i <= N; ++i){ solver.addedge(0,i,1,d[0][i]); solver.addedge(i+N,t,1,d[0][i]); solver.addedge(i,i+N,1,-INF); for(int j = i + 1; j <= N; ++j) solver.addedge(i + N,j,1,d[i][j]); } printf("%d\n",solver.mincost(s,t) + N * INF); } return 0; }
相关文章推荐
- HDU 4411 Arrest 费用流
- HDU 4411 Arrest(费用流)
- hdu-4411-Arrest-费用流
- 【HDU】4411 Arrest 费用流
- hdu 4411 Arrest 费用流模板
- HDU 4411 Arrest(费用流)
- hdu 4411 Arrest(费用流)
- HDU 4411 Arrest 费用流
- HDU 4411 Arrest 费用流
- hdu-4411-Arrest
- hdu 4411 Arrest【最小费用流】
- hdu 4411 Arrest (最小费用最大流)
- HDU 4411 - Arrest(网络流‘最小费用最大流)
- HDU 4411 费用流,诡异的构图
- hdu 4411 网络赛题目 费用流
- HDU 4411 arrest
- HDU 4411 Arrest
- hdu 4411 Arrest
- hdu 4411 Arrest
- hdu 4411 Arrest(最小费用最大流)