题目描述
一支分散的飞船舰队,需要汇合到主舰,但是这种飞船在太空中飞行的耗油与质量没有关系,只与发动机打开的时间有关系,为了节省油量,指挥官通知,汇合途中,多台飞船可以串成串飞行,这样只需启动一台发动机,由于安全因素飞船只能走某些航线(某飞船到某飞船的航线)。指挥发现这样的移动方案可能有多种,但最短汇合时间相同,指挥官想考察你是否知道在总耗油最小的情况下,最短多久汇合完毕。
输入
T(T<10)组数据每组第一行有一个整数N(飞船个数<=300),之后第一行是其他飞船到主舰的时间,再有n行,每行n个数Aij表示Ai到Aj的时间。(均在int范围内)
输出
每组数据输出总耗油最小的情况下,总耗油量与最短汇合时间。
样例输入
1 5 5 7 4 3 6 0 2 1 6 3 2 0 3 1 4 1 3 0 4 5 6 1 4 0 2 3 4 5 2 0
样例输出
9 7
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define maxn 305
using namespace std;
int n,m,p[maxn],e[maxn][maxn],pre[maxn];
struct road
{
int a,b;
int len;
}x[maxn*maxn];
int cmp(road a,road b)
{
return a.len<b.len;
}
void init()
{
for(int i=0;i<=n;++i)
{
p[i]=i;
}
}
int find(int x)
{
int r=x;
while(r!=p[r])
{
r=p[r];
}
int i=x,j;
while(i!=r)
{
j=p[i];p[i]=r;i=j;
}
return r;
}
int join(int x,int y)
{
int fx=find(x),fy=find(y);
if(fx!=fy)
{
p[fy]=fx;
return 1;
}
return 0;
}
void slove()
{
sort(x,x+m,cmp);
int sum=0,cnt=0;
for(int i=0;cnt<n;++i)//经典的最小生成树问题....
{
if(join(x[i].a,x[i].b))
{
++cnt;
sum+=x[i].len;
e[x[i].a][x[i].b]=x[i].len;
e[x[i].b][x[i].a]=x[i].len;
}
}
printf("%d ",sum);
}
int maxx=0;
void dfs(int x,int s){
for(int i=1;i<=n;i++){
if(e[x][i]&&!pre[i]){
pre[i]=1;
dfs(i,s+e[x][i]);
}
}
if(maxx<s) maxx=s;
}
int main(){
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
init();m=0;
memset(e,0,sizeof(e));
for(int i=0;i<=n;++i)//虚拟 0 号节点!!
{
for(int j=1;j<=n;++j)
{
int len;
scanf("%d",&len);
if(i<j)//一半的边就行,多了浪费
{
x[m].a=i,x[m].b=j;x[m].len=len;
++m;
}
}
}
memset(pre,0,sizeof(pre));
slove();
pre[0]=1;
dfs(0,0);
printf("%d\n",maxx);
}
return 0;
}