Santa Clauses and a Soccer Championship
【Point】
settle them in the minimum possible number of cities m in such a way
掉入了出题的陷阱当中,这道题目只需要一个休息站就可以了,具体分析见背景
权值最短路与多个休息点两个信息,起到了很好的误导作用。思路一直被限制在图论特别是Floyd上面
【BackGround】
The country Treeland consists of n cities connected with n - 1 bidirectional roads in such a way that it's possible to reach every city starting from any other city using these roads.
n个城市,由n-1条道路连通,类似于最小生成树?这说明没有多余的道路,每一条道路都至关重要(即,如果去掉一条道路,必然至少存在一个City无法与Other Cities 相连通),也就是从City A 到 City B只有一种走法。
又因为只要休息点安排在City A 与 City B的必由之路上,由于一来一回的两场比赛,那么,必然是最短路
鉴于以上两点,我们可以轻易地得出:所求的m个点是所有道路的交点
现在来论证(胡扯)m必定为1:题目中只是给出了k对的Team,但是没有指定具体的对阵名单,自然我们就可以随意指定了。
由题设可知,必然存在一个City,以此City作为分割,能够把Team分成两个部分,这两个部分的Team个数分别为k(若用以分割的City本身是含有一个Team,可把这个City归入其中某一个部分,则结论依然成立)。
这样,选中的City就成为了沟通两个部分不可或缺的“桥梁”,通过对分属“桥梁”两边的Team作一一映射,我们就完成了证明,且这时休息点,即为“桥梁”。
【Algorithm】
依照上面的思路,我们可以完成算法设计,但仍需要解决两个问题:
1、哪个点可以作为分割点?
2、当分割点存在多个分支道路的时候,我们应该把哪几条道路划分成一个部分,而把其它道路划分成另一部分呢?
秉承暴力解决是唯一真解的理念,再配合一点小聪明,就不必完全解决这两个问题,只需要假装部分完成,然后再说服自己就可以了。
回到问题本身,我们为什么要把Team分成两个均为k的部分?因为一一对应;那么,如果某一部分超过了k就会出现,内部解决,内部消化的问题,桥梁也无法构成“必由之路”,增加了m的大小。
对于大的整体部分是这样的,小的单条分支也都是这样,超过k这个分割点就是不成立的
也就是说我们只需要计算每个City 每条分支的上的Team个数,若超过k则不成立,<=k就符合条件
到此为止我们已经非常成功地解决了寻找分割点的问题,那么道路分配问题应该怎么解决呢?
其实,并不必解决,我们只需要对找到的分割点进行DFS处理即可,把前面k个点丢给Part I 后面 k个点丢个Part II,按照DFS的顺序一一对应就可以,这样的分割虽然与我们最开始提出的有所不同,但是同样可以起到很好的效果
【Code】
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 2e5 + 10;
vector<int> G[maxn];
int val[maxn];
int val_all_sons[maxn];
int n, k;
queue<int> q1, q2;
int dfs(int u, int fa)
{
int & use = val_all_sons[u];
int ans = 0;
for (int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if (v == fa) continue;
int tem = dfs(v, u);
use = max(use, tem);
ans += tem;
}
use = max(use, 2 * k - ans);
return ans + val[u];
}
void dfs_city(int u, int fa)
{
if (val[u])
{
if (q1.size() < k)
q1.push(u);
else
q2.push(u);
}
for (int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if (v == fa) continue;
dfs_city(v, u);
}
}
int main()
{
scanf("%d%d", &n, &k);
int u, v;
for (int i = 0; i < n - 1; i++)
{
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
int a;
for (int i = 0; i < 2 * k; i++)
scanf("%d", &a), val[a] = 1;
dfs(1, 0);
int out;
//if (k == 1) out = a;
for (int i = 1; i <= n; i++)
if (val_all_sons[i] <= k) out = i;
printf("1\n%d\n", out);
dfs_city(out, 0);
if (q2.size()) q2.push(out);
while (q1.size())
{
int c1, c2;
c1 = q1.front(), c2 = q2.front();
printf("%d %d %d\n", c1, c2, out);
q1.pop(), q2.pop();
}
return 0;
}
【Note】
无聊胡乱猜想,题目中给的是k Pair 而不是 2k Team 是不是在暗示什么呢?
Thanks For Watching
—END—