贫富差距「NOIP多校联考 2019」

【题目描述】
一个国家有 \(N\) 个公民,标记为 \(0,1,2,...,N-1\),每个公民有一个存款额。已知每个公民有一些朋友,同时国家有一条规定朋友间的存款额之差不能大于\(d\)。也就是说,\(a\)\(b\) 是朋友的话,\(a\)\(x\) 元的存款,\(b\)\(y\) 元,那么\(|x-y|\leq d\)。给定\(d\)值与\(N\)个人的朋友关系,求这个国家最富有的人和最贫穷的人的存款相差最大的可能值是多少?即求贫富差距的最大值的下界。若这个值为无穷大,输出\(-1\).

【输入格式】
多组测试数据,第一行一个整数 \(T\),表示测试数据数量,\(1\leq T\leq 5\) 每组测试数据有相同的结构构成。
每组数据的第一行两个整数 \(N\)\(d\),表示人数与朋友间存款差的最大值,其中 \(2\leq N\leq 50,0\leq d\leq 1000\). 接下来有一个 \(N\times N\) 的数组 \(A\),若 \(A[i][j]='Y'\)表示\(i\)\(j\)两个人是朋友,否则\(A[i][j]='N'\)表示不是朋友。其中 \(A[i][i]='N'\),且保证 \(A[i][j]=A[j][i]\).

【输出格式】
每组数据一行输出,即这个国家的贫富差距最大值的下界,如果这个值为无穷大输出\(-1\).

题解
看一下这个例子

(图画的不好)
给每对朋友之间连一条边权为\(d\)的无向边
这个例子中 4个人两两都是朋友 其实仔细观察可以发现 \(i\)\(j\) 之间的最大贫富差距就是他们之间的最短路 (这让我想到了差分约束)
再试几次 好像这个结论是对的
所以就最短路乱搞就行了 floyd dijkstra SPFA都行
证明可能有点类似差分约束 反正我不会证QWQ

然后 什么情况下最大贫富差距是无穷大呢
这个还是很容易看出来 当图中存在不止一个连通块的时候 贫富差距可以是无穷大
dfs一遍就完了

代码

#include <iostream>
#include <cstring> 
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;

ll read() {
    ll ret = 0, flag = 1;
    char ch = getchar();
    while (ch > '9' || ch < '0') {
        if (ch == '-') flag = -1;
        ch = getchar();
    }
    while (ch <= '9' && ch >= '0') {
        ret = (ret << 3) + (ret << 1) + (ch ^ '0');
        ch = getchar();
    }
    return ret * flag;
}

ll t, n, d, ans;
ll a[100][100];
char ch[100][100];
bool vis[1005];
ll dis[1005];

void dfs(ll x) {
    vis[x] = 1;
    for (int i = 1; i <= n; i++) {
        if (a[x][i] && !vis[i]) dfs(i);
    }
}

void SPFA(ll st) {
    queue<ll> q;
    q.push(st);
    while (!q.empty()) {
        ll x = q.front();
        q.pop();
        for (int i = 1; i <= n; i++) {
            if (a[x][i]) {
                if (dis[x] + d < dis[i]) {
                    dis[i] = dis[x] + d;
                    if (!vis[i]) {
                        q.push(i);
                        vis[i] = 1;
                    }
                }
            }
        }
        vis[x] = 0; 
    }
}

int main() {
    t = read();
    while (t--) {
        n = read(); d = read();
        ans = -1;
        for (int i = 1; i <= n; i++) {
            scanf("%s", ch[i] + 1);
        }
        for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) {
            if (ch[i][j] == 'Y') a[i][j] = 1;
            else a[i][j] = 0;
        }
        memset(vis, 0, sizeof(vis));
        dfs(1);
        bool flag = 1;
        for (int i = 1; i <= n; i++) {
            if (!vis[i]) {
                puts("-1");
                flag = 0;
                break;
            }
        }
        if (!flag) continue;
        
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) dis[j] = 0x7fffffff;
            memset(vis, 0, sizeof(vis));
            dis[i] = 0;
            vis[i] = 1;
            SPFA(i);
            for (int j = 1; j <= n; j++) {
                ans = max(ans, dis[j]);
            }
        }
        printf("%lld\n", ans);
    }   
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ak-dream/p/AK_DREAM14.html
今日推荐