题解
- 一开始时,一直在想如果找到与哪个黑点相连
- 可以考虑一下从建一个S源点,然后把黑点向S点连一条权值为0的边
- 然后我们就可以求出从S点到所有点的最短距离
- 问题就转换为了求白点到S的距离
- 从S出发往回dfs,找到最短路径上的边
- 一条边可能被多次经过,我们dfs可能会重复把边选出来,但题目要求一条边只加一次代价
- 所以可以用Kruskal,把边连起来,避免重复边
- 如果我们求的边权和ans==0,那么说明一条边也找不到,那么“impossible”
代码
1 #include<cstdio>
2 #include<iostream>
3 #include<cstring>
4 #include<cmath>
5 #include<algorithm>
6 #include<queue>
7 using namespace std;
8 const int inf=0x3f3f3f;
9 struct edge {long long to,from,v; }e[300010*2],k[300010*2];
10 long long dis[100010],ans,fa[100010],n,m,head[100010],cnt,tot;
11 bool f[100010];
12 queue<int>Q;
13 void insert(int x,int y,int z) { e[++cnt].to=y; e[cnt].from=head[x]; e[cnt].v=z; head[x]=cnt; }
14 void spfa()
15 {
16 memset(dis,inf,sizeof(dis));
17 memset(f,false,sizeof(f));
18 Q.push(0); dis[0]=0;
19 while (!Q.empty())
20 {
21 int u=Q.front(); Q.pop();
22 f[u]=false;
23 for (int i=head[u];i;i=e[i].from)
24 if (dis[u]+e[i].v<dis[e[i].to])
25 {
26 dis[e[i].to]=dis[u]+e[i].v;
27 if (!f[e[i].to])
28 {
29 Q.push(e[i].to);
30 f[e[i].to]=true;
31 }
32 }
33 }
34 }
35 void dg(int x)
36 {
37 for (long long i=head[x];i;i=e[i].from)
38 if (dis[x]+e[i].v==dis[e[i].to])
39 {
40 dg(e[i].to);
41 k[++tot].from=x,k[tot].to=e[i].to,k[tot].v=e[i].v;
42 }
43 }
44 long long getfather(int x)
45 {
46 if (fa[x]==x) return x;
47 return fa[x]=getfather(fa[x]);
48 }
49 void kruskal()
50 {
51 for (long long i=1;i<=tot;i++)
52 {
53 long long x=getfather(k[i].from),y=getfather(k[i].to);
54 if (x!=y)
55 {
56 ans+=k[i].v;
57 fa[y]=x;
58 }
59 }
60 }
61 bool cmp(edge x,edge y) { return x.from<y.from; }
62 int main()
63 {
64 scanf("%lld%lld",&n,&m);
65 for (int i=1;i<=n;i++)
66 {
67 int x;
68 scanf("%d",&x);
69 if (x==1) insert(0,i,0);
70 }
71 for (int i=1;i<=m;i++)
72 {
73 int x,y,z;
74 scanf("%d%d%d",&x,&y,&z);
75 insert(x,y,z); insert(y,x,z);
76 }
77 spfa();
78 dg(0);
79 sort(k+1,k+tot+1,cmp);
80 for (int i=1;i<=n;i++) fa[i]=i;
81 kruskal();
82 if (ans==0) printf("impossible"); else printf("%lld",ans);
83 }