其他分享
首页 > 其他分享> > AtCoder Beginner Contest 259

AtCoder Beginner Contest 259

作者:互联网

AtCoder Beginner Contest 259

https://atcoder.jp/contests/abc259

先把D放这里,其他的明天补上来

D - Circumferences

题源:abc259_d
人生中第一次做出D题于是就来发题解了

题目描述

给定n个圆(圆心坐标和半径r),以及起点和终点的坐标(这两点必在某个圆上)
已知 点可以沿着圆的边界(即在圆上移动),试判断能否从起点走到终点。

样例

Sample Input 1

4
0 -2 3 3
0 0 2
2 0 2
2 3 1
-3 3 3

Sample Output 1

Yes

Sample Input 2

3
0 1 0 3
0 0 1
0 0 2
0 0 3


Sample Output 2

No

分析

点一定是在圆上动的,所以当走到两圆交界处的时候就可以顺势走到另一个圆上。
(这里没法放图片,所以可以去原题看样例的截图来辅助来理解)
那么此时就等价于,在这两个圆之间建立一条无向边,于是问题就转化为:求 起点所在的圆 到 终点所在的圆的最短路

分析完毕,梳理一下要做的事:

  1. 找到起点和终点所在的圆的编号,记录为st和ed;
  2. 把所有两两相交的圆找到,然后建边(注意特判同心圆不可达的情况)
  3. 跑最短路的板子

Code

代码写的很潦草,轻喷
SPFA

#include <bits/stdc++.h>
#define int long long

using namespace std;
typedef pair<int, int> pii;
const int N = 3005*3005, inf = 1e18;
int h[N], ee[N], ne[N], w[N], idx;
int sx, sy, fx, fy, st = 0, ed = 0, n;
int dis[N];
bool vis[N];
//int a[N][N];

void add (int a, int b, int c) {
    ee[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
}

struct Node {
    int x, y, r;
    bool operator<(const Node &t)const {
        return x < t.x;
    }
}e[N];

void spfa () {
    queue<int>q;
    for (int i = 1; i <= n; i ++)   dis[i] = inf;
    dis[st] = 0;
    q.push(st);
    vis[st]  = true;
    
    while (!q.empty()) {
        int t = q.front();
        q.pop();
        vis[t] = false;
        
        for (int i = h[t]; i != -1; i = ne[i]) {
            int j = ee[i];
            if (dis[j] > dis[t]+ w[i]) {
                dis[j] = dis[t] + w[i];
                if (!vis[j])
                    q.push (j), vis[j] = true;
            }
        }
    }
    //for (int i = 1; i <= n; i ++)   cout << dis[i] << endl;
    // cout << dis[ed] << endl;

    if (dis[ed] != inf)  cout << "Yes\n";
    else    cout << "No\n";
}

signed main () {
    cin >> n;
    cin >> sx >> sy >> fx >> fy;
    for (int i = 1; i <= n; i ++) {
        int x, y, r;
        cin >> x >> y >> r;
        e[i] = {x, y, r}; 
    }
    //sort (e + 1, e + n + 1);

    for (int i = 1; i <= n; i ++) {
        if (st && ed)   break;
        int x = e[i].x, y = e[i].y, r = e[i].r;
        if ((x-sx)*(x-sx) + (y-sy)*(y-sy) == r*r)   st = i;
        if ((x-fx)*(x-fx) + (y-fy)*(y-fy) == r*r)   ed = i;
    }
    //cout << "st=" << st << ", ed=" << ed << endl;

    //建图
    memset (h, -1, sizeof h);
    for (int i = 1; i <= n; i ++) {
        int x = e[i].x, y = e[i].y, r = e[i].r;
        for (int j = i + 1; j <= n; j ++) {
            int xx = e[j].x, yy = e[j].y, rr = e[j].r;
            //if (x == xx && y == yy && r != rr)  continue;
            int d1 = (x-xx)*(x-xx) + (y-yy)*(y-yy);
            int d2 = (r+rr)*(r+rr);
            if (d1 != 0 && d1 <= d2) {
                //cout << "i=" << i << ", j=" << j << endl;
                add (i, j, 1), add (j, i, 1);
                //a[i][j] = a[j][i] = 1;
            }
        }
    }

    spfa ();
}

//走边框,看看能否走到
//z找圆的交点
//抽象建图,如果两个圆有交点的话就建立一条边

难得做出图论题...

标签:AtCoder,Beginner,idx,int,Sample,vis,259,圆上,dis
来源: https://www.cnblogs.com/CTing/p/16462299.html