HDU 4183 Pahom on Water (拆点最大流)
来源:互联网 发布:php源代码加密 原理 编辑:程序博客网 时间:2024/06/10 04:30
HDU 4183 Pahom on Water (拆点最大流)
tags: acm
做的时候和队友讨论了好久,总觉得最小生成树和最短路也有可能过,但最后还是选定了最大流.建图花了好久,然后发现交上去一直TLE,花了一个小时才查出来修改之前的从0到n-1的最大流代码的时候没有修改完全,导致一处循环判断条件出错一直循序,改正后AC.
题意:
给你一些平板的频率f,坐标(x,y),半径r,要求从f=400.0的点出发,经过有相交的平板,到达f=789.0的点,再回到f=400.0的点,要求除了起点外每个点最多只能访问一次,且到达f=789.0的点前只能从频率低的点到频率高的点,而回来的过程中只能从频率高的点到频率低的点.
问是否能够做到.
解析:
题目可转化为,在只存在从低到高的边的图上,起点(f=400.0)与终点(f=789.0)间是否存在两条不同的路径.
我们可以建立边容量为1且节点最大流量也为1的图,然后使用最大流求解源点和汇点之间的最大流量,流入汇点的流量即为从起点到终点不同的路径数.
边容量为1很容易做到,那节点最大流量要怎么控制呢?
这里就要用到一个建图技巧了.对于每一个顶点v,我们可以将其拆分为vi和vo两个顶点,所有指向v的边与vi相连,而所有由v出发的点由vo出发,同时vi与vo之间添加一条容量为k的边(此题容量为1),即可将通过顶点的容量限制为k以内.
最后输出最大流量即可.
如果使用的是Ford-Fulkerson的话还有一个小小的优化,因为每次标号-改进都代表一条独特的路径,最多只要增广两次就能得出答案,所以solve()函数中的循环只需要执行两次.
代码:
0 ms
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <map>#include <queue>using namespace std;#define MAXN 605#define INF 0x7f7f7f7f#define MIN(a,b) ((a)<(b)?(a):(b))struct NodeType{ double f; int x, y, r;}Node[MAXN];struct ArcType{ int c, f;};ArcType Edge[MAXN][MAXN];int n, m; //顶点数和弧数int vis[MAXN]; //顶点状态:-1--未标号,0--已标号未检查,1--已标号已检查int pre[MAXN]; //标号的第一个分量,标志当前顶点的标号由何处获得int alpha[MAXN]; //标号的第二个分量,标志可改进量alphaint s, t;/*** 默认s为源点,t为汇点**/void find_path(){ queue<int> Q; pre[s] = s; alpha[s] = INF; vis[s] = 1; Q.push(s); while (!Q.empty() && vis[t] == 0) { int u = Q.front(); Q.pop(); for (int i = 0; i < n; i++) { if (!vis[i]) { if (Edge[u][i].c < INF && Edge[u][i].f < Edge[u][i].c) { vis[i] = 1; pre[i] = u; alpha[i] = MIN(alpha[u], Edge[u][i].c - Edge[u][i].f); Q.push(i); } else if (Edge[i][u].c < INF && Edge[i][u].f >0) { vis[i] = 1; pre[i] = -u; alpha[i] = MIN(alpha[u], Edge[i][u].f); Q.push(i); } } } }}void update_flow(int a){ //根据可改进量修改流量 int v1 = t; int v2 = abs(pre[v1]); while (v1 != s) { if (Edge[v2][v1].c < INF) { Edge[v2][v1].f += a; } else if (Edge[v1][v2].c < INF) { Edge[v1][v2].f -= a; } v1 = v2; v2 = abs(pre[v1]); }}int solve(){ int x = 2; while (x--) //这个循环最多只需要2次 { //初始化标志数组 memset(vis, 0, sizeof(vis)); memset(pre, 0, sizeof(pre)); memset(alpha, 0, sizeof(alpha)); find_path(); if (vis[t] == 0 || alpha[t] == 0) { break; } update_flow(alpha[t]); } return Edge[s][s + n / 2].f; //汇点内部流量即为不同路径条数}int main(){ int N; int T; scanf("%d", &T); while (T--) { s = -1; t = -1; scanf("%d", &N); memset(Edge, 0x7f, sizeof(Edge[0])*(N*2+1)); n = N * 2; for (int i = 0; i < N * 2; i++) { Edge[i][i + N].c = 1; Edge[i][i + N].f = 0; } for (int i = 0; i < N; i++) { scanf("%lf %d %d %d", &Node[i].f, &Node[i].x, &Node[i].y, &Node[i].r); if (Node[i].f == 400.0) s = i; if (Node[i].f == 789.0) t = i; } Edge[s][s + N].c = N; Edge[s][s + N].f = 0; Edge[t][t + N].c = N; Edge[t][t + N].f = 0; for (int i = 0; i < N; i++) { for (int j = i + 1; j < N; j++) { if ((Node[i].r + Node[j].r)*(Node[i].r + Node[j].r) >= (Node[i].x - Node[j].x)*(Node[i].x - Node[j].x) + (Node[i].y - Node[j].y)*(Node[i].y - Node[j].y)) { if (Node[i].f < Node[j].f) { Edge[i + N][j].c = 1; Edge[i + N][j].f = 0; } else if (Node[i].f > Node[j].f) { Edge[j + N][i].c = 1; Edge[j + N][i].f = 0; } } } } int ans = solve(); if (ans >= 2) printf("Game is VALID\n"); else printf("Game is NOT VALID\n"); //printf("%d\n", ans); } return 0;}
0 0
- HDU 4183 Pahom on Water (拆点最大流)
- hdu 4183 Pahom on Water(最大流)
- hdu 4183 Pahom on Water 最大流
- HDU 4183 Pahom on Water 最大流
- hdu 4183 Pahom on Water (最大流)
- HDOJ 4183 - Pahom on Water 拆点最大流
- 【网络流】 HDU 4183 Pahom on Water 拆点
- hdu 4183 Pahom on Water 最大流 isap
- HDU 4183 Pahom on Water(最大流SAP)
- HDU -- 4183 Pahom on Water(最大流)
- HDU 4183--Pahom on Water【最大流dinic】
- hdu 4183 Pahom on Water(最大流)
- hdu 4183 Pahom on Water 网络流
- HDU 4183 Pahom on Water
- HDU 4183 Pahom on Water(点双连通分量)
- Pahom on Water HDU
- HDU 4183Pahom on Water(网络流之最大流)
- HDU 4183 Pahom on Water 来回走不重复点的网络流
- windows编程基础
- 认识/dev/shm
- Lily上课时使用字母数字图片教小朋友们学习英语单词,每次都需要把这些图片按照大小(ASCII码值从小到大)排列收好。请大家给Lily帮忙,通过C语言解决。
- Java 中的== 和equals()方法
- JS、JQuery和ExtJs的跨域处理
- HDU 4183 Pahom on Water (拆点最大流)
- java内存简析
- ural 1008. Image Encoding bfs
- 一些数学小思维Tips长期更新积累
- 计算字符串最后一个单词的长度,单词以空格隔开。
- 090 Subsets II [Leetcode]
- 树莓派安装TP-link wn725n网卡驱动
- sqlplus无法退格 (backspace)
- Java中内存泄露及垃圾回收机制