互测day3的T2,作为送分题出现
首先每个点都有两种决策,从别的点引水或者新建,所以我们可以增加一个超级源点。
然后每个源点向每个点都连边,每条边的边权是在这个点建立水库的费用
然后点之间互相连边,RT即可
最后一次最小生成树就可以了
选这个题的原因我想有很多,这个题编程复杂度几乎是0,思路也不算特别难想,但是对最小生成树的使用技巧又有一定要求,所以个人还是比较喜欢的
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct wbysr
{
int dist,num;
bool operator < (const wbysr &fuck)const
{
return dist>fuck.dist;
}
};
int n,i,m,d[10000+4],done[10000+4];
int main()
{
int num=0,p;
vector <int>aim[10000+4];
vector<int>w[10000+4];
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&p);
aim[0].push_back(i);
aim[i].push_back(0);
w[0].push_back(p);
w[i].push_back(p);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&p);
if(i!=j)
{
aim[i].push_back(j);
aim[j].push_back(i);
w[i].push_back(p);
w[j].push_back(p);
}
}
for(i=1;i<=n;i++)
d[i]=0x7fffffff;
d[0]=0;
memset(done,0,sizeof(done));
priority_queue<wbysr> q;
q.push((wbysr){0,0});
int ans=0;
while(!q.empty())
{
wbysr x=q.top();
q.pop();
int now=x.num;
if(done[now])
continue;
ans+=x.dist;
done[now]=1;
num++;
for(int k=0;k<aim[now].size();k++)
if(d[aim[now][k]]>w[now][k])
{
d[aim[now][k]]=w[now][k];
q.push((wbysr){d[aim[now][k]],aim[now][k]});
}
}
//cout<<d[n]<<endl;
int answer=0;
for(i=1;i<=n;i++)
answer+=d[i];
// printf("%d\n",num);
printf("%d",ans);
}