HDU4183 Pahom on Water(来回走最大流,一个点只经过一次)

题意:

有n个圆,每个圆的中心和半径和一个频率都给定,只有一个频率最高的789为紫色,只有一个最低的400为红色,规则如下:

1.当两个圆严格相交时,且人是从红色到紫色的方向运动时可以由低频率向高频率移动

2.当两个圆严格相交时,且人是从紫色到红色的方向运动时可以由高频率向低频率运动

3.除了红色的圆以外,离开某个圆之后就会消失(即只能走一次)

思路:

如果一开始红色和紫色就相交,则存在合理方案。否则

本题要求是先从红点出发,经过紫点之后再返回红点,如果以红点作为源点,网络流算法不能先到达一个T,然后再到达另一个T,

所以不妨以紫点作为源点sp,红点作为tp,将点拆分成i和i+n,然后建边(i, i+n, 1), (sp, sp+n, 2)如果两个圆严格相交,设i的频率

大于j的频率,则(i+n, j, 1)反之(j+n, i, 1),求出最大流为2则存在合理方案。把S(紫色) -> T(红色)的两个流中的一个流反向,就可以形成一个

T -> S -> T的方案。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 300 + 5;
const int inf = 0x3f3f3f3f;
struct point{
    double f;
    double x, y, r;
} p[maxn];
struct edge{
    int to, w, next;
} ed[maxn*maxn<<2];
int k, n, sp, tp;
int head[maxn<<1], tot, d[maxn<<1], maxflow;
inline void init(){
    memset( head, -1, sizeof(head) );
    tot = 1;
}

inline double getlen2( const point a, const point b ){
    double x1 = a.x, x2 = b.x;
    double y1 = a.y, y2 = b.y;
    return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}

inline bool judge(point a, point b){
    return getlen2(a, b) < (a.r+b.r)*(a.r+b.r);
}

inline void add( int u, int v, int w ){
    ed[++tot].to = v; ed[tot].w = w; ed[tot].next = head[u]; head[u] = tot;
    ed[++tot].to = u; ed[tot].w = 0; ed[tot].next = head[v]; head[v] = tot;
}

inline bool bfs(){
    memset( d, 0, sizeof(d) );
    queue<int> q;
    d[sp] = 1;
    q.push(sp);
    while( !q.empty() ){
        int x = q.front();
        q.pop();
        for( int i=head[x]; i!=-1; i=ed[i].next ){
            int y = ed[i].to;
            if( ed[i].w && !d[y] ){
                d[y] = d[x] + 1;
                q.push(y);
                if( y==tp ) return 1;
            }
        }
    }
    return 0;
}

inline int dfs( int x, int flow ){
    if( x==tp ) return flow;
    int res = flow, k;
    for( int i=head[x]; i!=-1&&res; i=ed[i].next ){
        int y = ed[i].to;
        if( ed[i].w && d[y]==d[x]+1 ){
            k = dfs( y, min( res, ed[i].w ) );
            if(!k) d[y] = 0;
            ed[i].w -= k;
            ed[i^1].w += k;
            res -= k;
        }
    }
    return flow - res;
}

inline void dinic(){
    int flow = maxflow = 0;
    while( bfs() ){
        while( flow = dfs(sp, inf) ) maxflow += flow;
    }
}

int main(){
    // freopen("in.txt", "r", stdin);
    scanf("%d", &k);
    while( k-- ){
        scanf("%d", &n);
        init();
        for( int i=1; i<=n; i++ ){
            scanf("%lf%lf%lf%lf", &p[i].f, &p[i].x, &p[i].y, &p[i].r);
            if( p[i].f==400.0 ) tp = i;
            else if( p[i].f==789.0 ) sp = i;
            else add( i, i+n, 1 );
        }
        if( judge( p[sp], p[tp] ) ){
            puts("Game is VALID");
            continue;
        }
        add( sp, sp+n, 2 );
        for( int i=1; i<=n; i++ )
            for( int j=i+1; j<=n; j++ ){
                if( judge(p[i], p[j]) ){
                    if( p[i].f<p[j].f ) add( j+n, i, 1 );
                    else add( i+n, j, 1 );
                }
            }
        dinic();
        // cout << maxflow << endl;
        if( maxflow>=2 ) puts("Game is VALID");
        else puts("Game is NOT VALID");
    }

    return 0;
}
/*
Game is NOT VALID
Game is VALID
 */

原文地址:https://www.cnblogs.com/WAautomaton/p/11143483.html

时间: 2024-10-29 02:42:53

HDU4183 Pahom on Water(来回走最大流,一个点只经过一次)的相关文章

HDU 4183 Pahom on Water 来回走不重复点的网络流

题目来源:HDU 4183 Pahom on Water 题意:若干个区域 每个区域有一个值 区域是圆 给出圆心和半径 从起点(值为400.0)到终点(值为789.0)满足走相交的圆 并且值必须递增 然后从终点到起点 值必须递减 此外区域只能去一次 思路:建图 相互能走的区域连一条边 因为只能走一次 所以拆点 如果没有来回 只有去 那么判断最大流为1即可 现在还要回来 并且回来的条件和去的条件想法(一个递增一个递减)可以反向考虑给源点cap=2 最大流为2 #include <cstdio>

hdoj 4183 Pahom on Water 【基础最大流】

题目:hdoj 4183 Pahom on Water 题意:题目有点长,读懂了就是个水的最大流,每次从789开始到400,走的话必须是两个圆相交而且频率递增的,每个点只走一次,求有没有满足这样条件的. 分析:题目读懂就比较水了.直接按照题目意思建图,初始点和结束点容量为2,其他点只走一次容量为1,然后求最大流. AC代码: #include <cstdio> #include <cstring> #include <iostream> #include <str

HDU 4183 Pahom on Water(最大流SAP)

Pahom on Water Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 629    Accepted Submission(s): 288 Problem Description Pahom on Water is an interactive computer game inspired by a short story of

hdoj 4183 Pahom on Water

Pahom on Water Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 772    Accepted Submission(s): 355 Problem Description Pahom on Water is an interactive computer game inspired by a short story of

HDU 4183Pahom on Water(网络流之最大流)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4183 这题题目意思很难看懂..我看了好长时间也没看懂..最终是从网上找的翻译..我就在这翻译一下吧. 意思大约是:有多个点,每个点给出坐标与半径,加入两个点相交,就可以从这两个点走.题目要求先从起点到终点,再从终点回到起点.从起点到终点的过程中,只能从频率小的走到频率大的点(前提是两点相交),从终点到起点的过程中,只能从频率大的走到频率小的.在走的过程中,除了起点与终点,别的只要走过就会消失,就是说

也应有泪流知己,只觉无颜对俗人

这段时间我放下了游戏,放下了妹子(压根没有过),稍显孤独,有钱却不敢花,日子过得还真是,,,,有点自讨苦吃. 原谅我最近着了魔,突然感觉自己的钱如果不用来买学习资源,那就是浪费money.--不小心又装了个逼. 以下正文 最近看了一本书,王鼎钧先生的<讲理>,虽然感觉已经不是我这年龄段的人看了,但也不免有些感慨. 其一便是先生写在前面的序,其中先生回答了这样一个问题:身为散文大家,为什么降低姿势,写这样的书籍呢? 其言道:我是赤着脚走路的那种人,路上没有红毯,只有荆棘.中年以后整理自己的生活经

HDU 4183 Pahom on Water(最大流)

https://vjudge.net/problem/HDU-4183 题意: 这道题目的英文实在是很难理解啊. 给出n个圆,每个圆有频率,x.y轴和半径r4个属性,每次将频率为400的圆作为起点,频率为789点作为终点.从源点到汇点时必须从频率小的到频率大的,而从汇点到源点时必须从频率大的到频率小的.前提时这两个圆必须严格相交.每个点只能走一次.判断是否能从起点出发到达终点,并再次返回起点. 思路: 其实就是判断最大流是否大于等于2.因为每个点只能走一次,用拆点法. 1 #include<io

【网络流】 HDU 4183 Pahom on Water 拆点

题意:求两条路 能从 400.0 -> 789.0 且这两条路不想交(除了端点400,789 ) 求只能走一次的网络流需要用到拆点, 将点i  拆成 i 和 i+n  i->i+n的容量为经过的次数  (这题为1 ) 若i 能到达 j  则连接 i+n-> j #include <cstdio> #include <cstring> #include <cstdlib> #include <string> #include <iost

【HDOJ】4183 Pahom on Water

就是一个网络流.red结点容量为2,查看最大流量是否大于等于2.对于条件2,把边反向加入建图.条件1,边正向加入建图. 1 /* 4183 */ 2 #include <iostream> 3 #include <string> 4 #include <map> 5 #include <queue> 6 #include <set> 7 #include <stack> 8 #include <vector> 9 #inc