标签:最小生成树
其实就是一道最小生成树的题目.我们只需要将坏点排除在外,然后对其它点做一次最小生成树,然后在将坏点连接到这颗生成树上(每次都选代价最小的点).当然如果最后不是所有的点都连接到一起,就是impossible了.
还有一种情况需要特判,就是如果一共只有两个点,并且都是坏点,这种情况也是合法的.
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define maxn 210000
#define ll long long
#define INF 0x3f3f3f3f
vector<int>g[maxn],w[maxn];
typedef struct
{
int x,y,w;
}P;
P p[maxn];
int cmp(P p1,P p2)
{
return p1.w<p2.w;
}
int e,fa[maxn];
int a[maxn],flag[maxn];
int Find(int x)
{
return fa[x]==x?x:Find(fa[x]);
}
///如果只有两个点,且全部是坏点则要特判
int main()
{
int n,m,k;
// freopen("in.txt","r",stdin);
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
int h;
memset(flag,0,sizeof(flag));
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=n;i++)
g[i].clear(),w[i].clear();
for(int i=0;i<k;i++)
{
scanf("%d",&a[i]);
flag[a[i]]=1;
}
e=0;
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(k==2&&x==a[0]&&y==a[1]) h=z;
if(k==2&&y==a[0]&&x==a[1]) h=z;
p[e].x=x; p[e].y=y; p[e].w=z; e++;
p[e].x=y; p[e].y=x; p[e].w=z; e++;
g[x].push_back(y); w[x].push_back(z);
g[y].push_back(x); w[y].push_back(z);
}
if(n==2&&k==2)
{
printf("%d\n",h);
continue;
}
sort(p,p+e,cmp);
int cnt=1;
bool bl=true;
ll ans=0;
for(int i=0;i<e;i++)
{
int x=p[i].x,y=p[i].y;
if(!flag[x]&&!flag[y])
{
int xx=Find(x);
int yy=Find(y);
if(xx!=yy)
{
ans+=p[i].w; cnt++;
fa[xx]=yy;
}
}
}
if(cnt<n-k) bl=false;
int sum1=0,sum2=0;
for(int i=0;i<k;i++)
{
int x=a[i],y,tmp=INF;
for(int j=0;j<g[x].size();j++)
{
y=g[x][j];
if(flag[y])
continue;
if(tmp>w[x][j])
tmp=w[x][j];
}
if(tmp<INF)
ans+=tmp,cnt++;
}
if(cnt<n) bl=false;
if(!bl)
printf("impossible\n");
else
printf("%lld\n",ans);
}
return 0;
}
CSUOJ--1633 Landline Telephone Network
标签:最小生成树
原文地址:http://blog.csdn.net/acm_lkl/article/details/45955071