【J Z O J】 /【G M O J 】2529.间谍派遣 题解
做了好久,终于做出来了!!!间谍:“我要拯救世界!!”
题目大意
题目描述
你是M,一个雇佣N个标号为从1到N的间谍的情报机关的总管。每个间谍被派往不同的国家并在那获取重要情报。
如下是你的任务:
1.在部分间谍间组织会面。每次会面在两个间谍间进行,两个间谍交换他们自己获取的或从之前会面中得到的信息。因为在不同国家的两个间谍间组织机密会面很困难,所以每次秘密会面都有一个费用。
2.当所有会面结束后,选择一部分间谍参加拯救世界的任务。一个间谍k参加此项任务需要花费Mk。很重要的一点是,任务要成功,必须满足参加任务的间谍获取的情报聚集到一起包含了其他剩余间谍所有的信息。
请找出完成任务的最小花费,即组织会面和派遣间谍的费用之和。
输入
输入的第一行包含正整数N,表示间谍数目(2≤N≤1000)。
接下来的N行包含N个不超过10^6的非负整数。在k行m列的数字表示间谍k和m间会面的花费,同样的,与m行k列的数字相等,k=m时数字为0。
接下来的一行包含N个正整数Mk(1≤Mk≤10^6),分别为派遣间谍1,2,…,N参加任务的花费。
输出
只有一行,为所需的最小总费用。
样例输入输出
输入1:
3
0 6 9
6 0 4
9 4 0
7 7 7
输出1:
17
输入2:
3
0 17 20
17 0 10
20 10 0
15 9 12
输出2:
34
输入3:
5
0 3 12 15 11
3 0 14 3 20
12 14 0 11 7
15 3 11 0 15
11 20 7 15 0
5 10 10 10 10
输出3:
28
思路
最小生成树!这题,先把他 n×n 的图用结构体储存好。我们按照样例1的 n×n 画个图:
我们虽然可以求出上图的最小生成树,但是间谍派遣去做任务又怎么算呢?我们可以新建一个点0,表示每个间谍去做任务的代价,然后做个最小生成树,如下图:
求这个图的最小生成树,先排个序,显然,取权值为4,为6,再选随便一条权值为7的三条边最优,选的时候要注意,两个点不得直接相连或间接相连,不然会形成回路,可以用并查集做这道题。
CODE
PS:记得开 long long !
注意:抄代码有害健康!
#include<bits/stdc++.h>
using namespace std;
long long n,tot;
long long ans;
long long fa[100005];
struct node{
long long x,y;
long long sum;
}a[1001005];
long long find(long long x)
{
if(fa[x]==x)
return x;
else
return fa[x]=find(fa[x]);
}
void pl(long long l,long long r)
{
long long i=l,j=r;
long long mid=a[(l+r)/2].sum;
while(i<=j)
{
while(a[i].sum<mid)
i++;
while(a[j].sum>mid)
j--;
if(i<=j)
{
swap(a[i],a[j]);
i++;
j--;
}
}
if(j>l)
pl(l,j);
if(i<r)
pl(i,r);
}
int main()
{
long long x;
scanf("%lld",&n);
for(long long i=1;i<=n;i++)
for(long long j=1;j<=n;j++)
{
scanf("%lld",&x);
if(j>i)
{
a[++tot].x=i;
a[tot].y=j;
a[tot].sum=x;
}
}
for(long long i=1;i<=n;i++)
{
fa[i]=i;
scanf("%lld",&x);
a[++tot].sum=x;
a[tot].x=0;
a[tot].y=i;
}
pl(1,tot);
for(long long i=1;i<=tot;i++)
{
long long f1=find(a[i].x),f2=find(a[i].y);
if(f1==f2) continue;
fa[f1]=f2;
ans+=a[i].sum;
}
printf("%lld",ans);
return 0;
}
最后
让我们一起辅助间谍拯救世界吧。