51nod 1366 贫富差距【并查集+Floyd】

    xiaoxiao2021-12-14  41

    1366 贫富差距 题目来源:  TopCoder 基准时间限制:1 秒 空间限制:131072 KB 分值: 40  难度:4级算法题 一个国家有N个公民,标记为0,1,2,...,N-1,每个公民有一个存款额。已知每个公民有一些朋友,同时国家有一条规定朋友间的存款额之差不能大于d。也就是说,a和b是朋友的话,a有x元的存款,b有y元,那么|x-y|<=d。给定d值与N个人的朋友关系,求这个国家最富有的人和最贫穷的人的存款相差最大的可能值是多少?即求贫富差距的最大值的下界。若这个值为无穷大,输出-1. Input 多组测试数据,第一行一个整数T,表示测试数据数量,1<=T<=5 每组测试数据有相同的结构构成。 每组数据的第一行两个整数N,d,表示人数与朋友间存款差的最大值,其中2<=N<=50,0<=d<=1000. 接下来有一个N*N的数组A,若A[i][j]='Y'表示i与j两个人是朋友,否则A[i][j]='N'表示不是朋友。其中A[i][i]='N',且保证 A[i][j]=A[j][i]. Output 每组数据一行输出,即这个国家的贫富差距最大值的下界,如果这个值为无穷大输出-1. Input示例 3 3 10 NYN YNY NYN 2 1 NN NN 6 1000 NNYNNN NNYNNN YYNYNN NNYNYY NNNYNN NNNYNN Output示例 20 -1 3000

    思路:

    1、首先我们考虑这样一种情况:

    4 d

    NYNN

    YNNN

    NNNY

    NNYN

    很显然此时1和2是朋友,3和4是朋友,但是我们无法通过一个人的金钱数来判断其他所有人的金钱数,那么对应这种情况就是-1.

    那么我们使用并查集来判断,是否整个图是连通的,如果不是连通的,那么对应输出-1.如果是连通的,我们继续处理。

    2、对应我们有一个关系网络,是一个连通图,并且我们已知两个直接朋友之间的贫富差距最大为D,那么我们只要找到了一条最长路,那么我们对应就可以设定起点的金钱数为x,那么终点的金钱数就是x+d*最长路的长度。

    因为点的个数不多,那么我们暴力处理两点间最短距离使用Floyd算法即可,然后我们枚举维护一条最长路。答案就是最长路的长度*d。

    建图的时候只要把Y的地方设定两点之间距离为1即可。

    Ac代码:

    #include<stdio.h> #include<string.h> #include<iostream> using namespace std; char a[55][55]; int map[55][55]; int f[55]; int n,d; int find(int a) { int r=a; while(f[r]!=r) r=f[r]; int i=a; int j; while(i!=r) { j=f[i]; f[i]=r; i=j; } return r; } void merge(int a,int b) { int A,B; A=find(a); B=find(b); if(A!=B) f[B]=A; } int judge() { for(int i=0;i<n;i++)f[i]=i; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { if(map[i][j]==1) { merge(i,j); } } } int cnt=0; for(int i=0;i<n;i++) { if(f[i]==i)cnt++; } if(cnt==1)return 1; else return 0; } int main() { int t; scanf("%d",&t); while(t--) { memset(map,0x3f3f3f3f,sizeof(map)); scanf("%d%d",&n,&d); for(int i=0;i<n;i++)map[i][i]=0; for(int i=0;i<n;i++) { scanf("%s",a[i]); for(int j=0;j<n;j++) { if(a[i][j]=='Y')map[i][j]=1; } } if(judge()==0) { printf("-1\n"); continue; } for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { for(int k=0;k<n;k++) { map[j][k]=min(map[j][k],map[j][i]+map[i][k]); } } } int output=-1; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { if(map[i][j]==0x3f3f3f3f||i==j)continue; output=max(output,map[i][j]); } } if(output==-1)printf("-1\n"); else printf("%d\n",output*d); } } 效率榜第一的思路:

    如果我们一个图保证是连通的,那么对应Floyd求出的最短路一定没有inf这一种情况发生,那么对应维护最大值的时候,如果最终维护出来的最大值是inf,那么对应一定就是因为整个图不连通的原因,那么对应此时输出-1即可。

    (优化了大部分代码量啊................(还是我太天真,为毛非要用个并查集呢));

    Ac代码(感谢效率榜第一mostleg分享的代码):

    #include <cstdio> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <set> #include <cmath> #include <stack> using namespace std; int n,d; string con[50]; int dis[50][50]; void init() { cin >> n >> d; for (int i = 0; i < n; i++) { cin >> con[i]; } } int work() { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { dis[i][j] = (con[i][j] == 'Y' ? 1 : 9999); } dis[i][i] = 0; } for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); } } } int cur = 0; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { cur = max(dis[i][j], cur); } } if (cur >= n) { return -1; } return cur * d; } int main() { int T; cin >> T; for (; T; T--) { init(); cout << work() << endl; } return 0; }

    转载请注明原文地址: https://ju.6miu.com/read-971778.html

    最新回复(0)