import java.util.*;
class Edge {
int to;
int nxt;
Edge(int t,int n) {
to = t;
nxt = n;
}
}
public class Main {
static void addEdge (int u,int v,int[] head,Edge[] edges,int[] e_cnt) {
edges[e_cnt[0]] = new Edge(v,head[u]);
head[u] = e_cnt[0]++;
edges[e_cnt[0]] = new Edge(u,head[v]);
head[v] = e_cnt[0]++;
}
static int find(int x,int[] pre) {
if (x != pre[x])
pre[x] = find(pre[x],pre);
return pre[x];
}
static void join(int x,int y,int[] pre,int[] cnt) {
int fx = find(x,pre);
int fy = find(y,pre);
if (fx != fy) {
pre[fy] = fx;
cnt[fx] += cnt[fy];
}
}
static long bonus(long n) {
if (n < 2) return 0;
return n*(n-1)/2;
}
public static void main(String[] args) {
//input
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
char[] dot = new char[n+1];
dot = in.next().toCharArray();
//construct graph
int[] head = new int[n+1];
Edge[] edges = new Edge[2*m+1];
int[] e_cnt = {0};
Arrays.fill(head,-1);
for (int i = 1; i <= m; ++i) {
int u = in.nextInt();
int v = in.nextInt();
addEdge(u,v,head,edges,e_cnt);
}
//connected block
int[] pre = new int[n+1];
int[] cnt = new int[n+1];
for (int i = 1;i <= n;++i) {
pre[i] = i;
cnt[i] = 1;
}
for (int u = 1; u <= n; ++u) {
if (dot[u-1] == '0') continue;
for (int i = head[u]; i != -1; i = edges[i].nxt) {
int v = edges[i].to;
if (dot[v-1] == '0') continue;
join(u,v,pre,cnt);
}
}
//cal now bonus
long ans = 0;
long[] blockBonus = new long[n+1];
for (int u = 1; u <= n; ++u) {
if (dot[u-1] == '0') continue;
if (pre[u] != u) continue;
int fu = find(u,pre);
blockBonus[fu] = bonus(cnt[fu]);
ans += blockBonus[fu];
}
//find the max node
int maxNode = 0;
long maxBonus = 0;
for (int u = 1;u <= n;++u) {
if (dot[u-1] == '1') continue;
dot[u-1] = '1';
long theBonus = ans;
HashSet<Integer> set = new HashSet<>();
for (int i = head[u]; i != -1; i = edges[i].nxt) {
int v = edges[i].to;
if (dot[v-1] == '0') continue;
set.add(find(v, pre));
}
int theCnt = 0;
for (int obj:set) {
theCnt += cnt[obj];
theBonus -= blockBonus[obj];
}
theBonus += bonus(theCnt+1);
dot[u-1] = '0';
if (theBonus > maxBonus) {
maxNode = u;
maxBonus = theBonus;
}
}
System.out.println(maxNode+" "+maxBonus);
}
}
其实这道题写了一天才A掉。一开始我不知道使用并查集来查连通块,尝试使用BFS查连通块,然后好像原理上可行,但是我想的是建立一个新的图(贸易图),每个连通块都是一个完全图。但是这样空间复杂度太高了,存不下。所以还是换成并查集了。
并查集我也调了一段时间,这里用到了cnt和blocksize分别记录每个连通块的大小和每个连通块的利润。还算是比较典型的题目了,可以当模板题。维护cnt[]的时候我一开始只用cnt[]++,结果一开始的数据比较小都能过,大数据过不了,所以头疼不知道哪错了。后来改成cnt[fx]+=cnt[fy]就可以了。以后遇到这种情况可以详细查看代码里的++是不是有点想的狭隘了。
这种图论的题目,具体算法逻辑其实不难,实现的时候有点麻烦就是了。要有耐心呀

京公网安备 11010502036488号