structnode{ int dis, u, f; booloperator<(const node& b) const { return dis > b.dis; } }; priority_queue<node> q; int dis[101]; bool vis[101];
int s, t;
booldijkstra(){ memset(dis, 0x3f, sizeof dis); memset(vis, 0, sizeof vis); dis[s] = 0; q.push({0, s, 0}); while (!q.empty()) { int u = q.top().u, f = q.top().f; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int v = 1; v <= n; v++) { if (!g[u][v]) continue; if (u == s && v == t) continue; if (u == t && v == s) continue; if (u != s && flg[u][f] == flg[u][v]) continue; if (dis[v] > dis[u]+g[u][v]) { dis[v] = dis[u]+g[u][v]; q.push({dis[v], v, u}); } } } return dis[t]!=0x3f3f3f3f; }
intmain(){ cin >> n; for (int i = 1; i <= n; i++) { int k, v, n1s, n2s, x; cin >> k >> v >> n1s >> n2s; for (int i = 1; i <= n1s; i++) { cin >> x; g[k][x] += v, g[x][k] += v; flg[k][x] = 0; } for (int i = 1; i <= n2s; i++) { cin >> x; g[k][x] += v, g[x][k] += v; flg[k][x] = 1; } } int ans = 0x3f3f3f3f; for (s = 1; s <= n; s++) { for (t = s+1; t <= n; t++) { if (!g[s][t]) continue; if (dijkstra()) { ans = min(ans, (g[s][t]+dis[t])/2); } } } cout << ans; }
intmain(){ scanf("%d", &n); if (n == 1) returnprintf("-1")&0; // 无解 for (int i = 1; i <= n; i++) { mine[i] = 2; } int st = -1; for (int i = 1; i <= n; i++) { scanf("%d", a+i); mine[a[i]]--; } for (int i = 1; i <= n && st == -1; i++) if (mine[i] == 2) st = i; for (int i = 1; i <= n; i++) { for (int j = mine[i]-(i==st); j >= 1; j--) q.push(i); }
if (st == -1) { // 没有成对的牌 printf("%d\n%d", n+2, a[n]); for (int i = 1; i < n; i++) printf(" %d", a[i]); printf(" %d %d", a[1], a[1]); return0; }
printf("%d\n%d", n, st); mine[st]--; push(st); push(a[1]); for (int i = 2; i <= n; i++) { int x = a[i]; if (mine[x] || cnts[x]) { // 有威胁。清空牌堆 printf(" %d", s[1]); pop(s[1]); } else { if (q.front() == s[1]) { // 会误收牌堆 q.push(q.front()); // 将队首移到队尾 q.pop(); } int nxt = q.front(); printf(" %d", nxt); if (cnts[nxt]) { pop(nxt); } else { push(nxt); mine[nxt]--; q.pop(); } } push(x); } }
因为这道题只要求最大的节点数量,所以我们只用枚举“根节点”的位置,然后判断是否对称,如果对称,统计这棵子树的节点数并记录 ans 。 cnt 与 main 函数过于简单故不在此处展开赘述,单独看看 same 函数——判断是否对称。我们一次需要两个位置来判断对称,而这两棵子树对称,当且仅当它们的儿子们全部对称,便可以从此处向下递归。递归的两边就是同时向内收 (ls[RootR],rs[RootL]) 或同时向外放 (ls[RootL],rs[RootR]),如果不这样的话遍历的两个位置本身就不对称。基于此,我们再来看实现。
实现
在代码实现方面,存树我们使用两个列表 ls 与 rs,这里开成了一个结构体,除此之外,我们还需要一个 id 用于存储树上节点的 value 。其余部分和思路部分所论述的一样。