我在interviewstreet.com上看到了这个问题
机器再一次袭击了Xions王国。王国 Xions有N个城市和N-1个双向道路。道路网络是 这样,任何一对城市之间都有一条独特的道路。
Morpheus有消息说K Machines正计划摧毁它 整个王国。这些机器最初生活在K不同的地方 王国的城市,从现在起他们可以随时计划和发射 攻击。所以他要求Neo摧毁一些破坏的道路 机器之间的连接,即在那里摧毁那些道路之后 不应该是任何两台机器之间的任何路径。由于攻击可以从现在开始,Neo必须完成这项任务 尽可能快地。王国的每条道路都需要一定的时间 被摧毁,他们只能一次摧毁一个。
您需要编写一个程序,告诉Neo最短的时间 他将要求破坏机器之间的联系。
示例输入输入的第一行包含两个空格分隔的行 整数,N和K.城市编号为0到N-1。然后按照N-1 每行包含三个空格分隔的整数x y z 意味着有一条连接城市x和城市y的双向道路,和 摧毁这条路需要z个单位的时间。然后按照K行 每个都包含一个整数。 Ith integer是第i个城市的id 机器目前位于。
输出格式在一行中打印所需的最短时间 破坏机器之间的连接。
示例输入
5 3 2 1 8 1 0 5 2 4 5 1 3 4 2 4 0
示例输出
10
解释Neo可以摧毁连接城市2和城市4的道路 重量5,连接城市0和城市1的重量5的道路 一次只能摧毁一条道路,总的最短时间 是10个单位的时间。在摧毁这些道路后没有机器 可以通过任何路径到达其他机器。
约束
2 <= N <= 100,000 2 <= K <= N 1 <= time to destroy a road <= 1000,000
有人可以说明如何处理解决方案。
答案 0 :(得分:2)
王国有N个城市,N-1边缘并且它完全连通,因此我们的王国是tree(在图论中)。在此图片中,您可以看到输入图形的树形表示,其中机器由红色顶点表示。
顺便说一下,您应该考虑从根顶点到所有叶节点的所有路径。因此,在每个路径中,您将拥有多个红色节点,并且在删除边缘期间,您应该仅考虑相邻的红色节点。例如,在路径0-10中,有两个有意义的对 - (0,3)和(3,10)。并且您必须从成对连接顶点的每个路径中精确删除一个节点(不少于,不多于)。
我希望这个建议很有帮助。
答案 1 :(得分:2)
正如其他人所说,具有N个顶点和N-1个边的连通图是树。
这种问题需要贪婪的解决方案;我要修改Kruskal's algorithm:
从一组N个组件开始 - 每个节点(城市)1个。跟踪哪些组件包含机器占用的城市。
一次取1条边(道路),按重量减少排序(从破坏成本最高的道路开始)。对于此边缘(必须连接两个组件 - 图形是树):
- 如果两个neigboring组件都包含机器占用的城市,则必须销毁此道路,并将其标记为
- 否则,将neigboring组件合并为一个。如果其中一个包含机器占用的城市,合并的组件也是如此。
完成所有边缘后,返回被破坏道路的成本总和。
复杂性与Kruskal算法相同,即对于精心挑选的数据结构和排序方法几乎是线性的。
答案 2 :(得分:2)
pjotr有一个正确的答案(虽然不是非常渐近最优)但是这句话
这类问题需要贪婪的解决方案
确实需要证据,就像在现实世界中一样(与竞争性编程区分开来),贪婪解决方案不是最佳的“种类”有几个问题(例如,这一点一般图中的问题,称为多端切割并且是NP难的)。在这种情况下,证据包括验证matroid公理。如果图形(V,E∖A)具有正确的| A |,则让一组边A A E 独立。 + 1个连接组件,至少包含一台机器。
空集的独立性。琐碎。
遗传财产。让A成为一个独立的集合。每个边e∈A连接图的两个连通分量(V,E∖A),每个连通分量至少包含一台机器。将e放回图表中,包含至少一台机器的连接组件数量减少1,因此A∖{e}也是独立的。
增强属性。让A和B成为| A |的独立集合&LT; | B |。由于(V,E∖B)具有比(V,E∖A)更多的连通分量,因此存在一对机器u,v,使得u和v由B而不是A断开。因为那里正好是从u到v的一条路径,B在此路径上至少包含一条边e,A不能包含e。删除A∪{e}会导致另一个连接组件包含至少一台机器而不是A,因此A∪{e}是独立的,视需要而定。
答案 3 :(得分:2)
所有这三个答案都将导致正确的解决方案,但您无法在interviewstreet.com提供的时间限制内完成解决方案。你必须想到一些简单的方法来成功解决这个问题。
提示:从机器所在的节点开始。
答案 4 :(得分:0)
开始从任一机器节点执行DFS。此外,到目前为止,用最小重量跟踪边缘。只要找到包含机器的下一个节点,就删除到目前为止记录的最小边缘。现在从这个新节点启动DFS。 重复,直到找到机器所在的所有节点。
应该是O(N)那样!!
答案 5 :(得分:-5)
我写了一些代码,并粘贴了所有测试。
#include <iostream>
#include<algorithm>
using namespace std;
class Line {
public:
Line(){
begin=0;end=0; weight=0;
}
int begin;int end;int weight;
bool operator<(const Line& _l)const {
return weight>_l.weight;
}
};
class Point{
public:
Point(){
pre=0;machine=false;
}
int pre;
bool machine;
};
void DP_Matrix();
void outputLines(Line* lines,Point* points,int N);
int main() {
DP_Matrix();
system("pause");
return 0;
}
int FMSFind(Point* trees,int x){
int r=x;
while(trees[r].pre!=r)
r=trees[r].pre;
int i=x;int j;
while(i!=r) {
j=trees[i].pre;
trees[i].pre=r;
i=j;
}
return r;
}
void DP_Matrix(){
int N,K,machine_index;scanf("%d%d",&N,&K);
Line* lines=new Line[100000];
Point* points=new Point[100000];
N--;
for(int i=0;i<N;i++) {
scanf("%d%d%d",&lines[i].begin,&lines[i].end,&lines[i].weight);
points[i].pre=i;
}
points[N].pre=N;
for(int i=0;i<K;i++) {
scanf("%d",&machine_index);
points[machine_index].machine=true;
}
long long finalRes=0;
for(int i=0;i<N;i++) {
int bP=FMSFind(points,lines[i].begin);
int eP=FMSFind(points,lines[i].end);
if(points[bP].machine&&points[eP].machine){
finalRes+=lines[i].weight;
}
else{
points[bP].pre=eP;
points[eP].machine=points[bP].machine||points[eP].machine;
points[bP].machine=points[eP].machine;
}
}
cout<<finalRes<<endl;
delete[] lines;
delete[] points;
}
void outputLines(Line* lines,Point* points,int N){
printf("\nLines:\n");
for(int i=0;i<N;i++){
printf("%d\t%d\t%d\n",lines[i].begin,lines[i].end,lines[i].weight);
}
printf("\nPoints:\n");
for(int i=0;i<=N;i++){
printf("%d\t%d\t%d\n",i,points[i].machine,points[i].pre);
}
}