求举反例或者反例情况
//思路:先在代价最少的地方凿井
//然后贪心找边,把边加到优先队列里面
//接着向外扩展农场,扩展了(n-1)个农场就结束了
#include<bits/stdc++.h>
using namespace std;
const int N=305;
int n;
int w[N];
int ans=0,vissum=0;
struct Edge1{//存图
int end,w;
Edge1(int end=0,int w=0):end(end),w(w){}
};
Edge1 g[N][N];
struct Edge{
int u,v,w;
Edge(int u=0,int v=0,int w=0):u(u),v(v),w(w){}
};
struct cmp{
bool operator()(const Edge& a,const Edge& b){
return a.w>b.w;
}
};
bool vis[N];
void addedge(priority_queue<Edge,vector<Edge>,cmp>&,int);
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>w[i];
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
cin>>g[i][j].w,g[i][j].end=j;
sort(g[i]+1,g[i]+n+1,[](const Edge1& a,const Edge1& b){
return a.w<b.w;//对每个点排序,按边长排序
});
}
int x=1;
for(int i=2;i<=n;i++){
if(w[i]<w[x])x=i;//找最小w的起点
}
ans=w[x];
vis[x]=1;
vissum++;
priority_queue<Edge,vector<Edge>,cmp> q;
addedge(q,x);
while(!q.empty()&&vissum<n){
Edge tmp=q.top();
q.pop();
if(vis[tmp.u]){//tmp的端点u访问过了
if(vis[tmp.v])continue;
vis[tmp.v]=1;
vissum++;
ans+=min(tmp.w,w[tmp.v]);//tmp.v这个点扩展到了,可能是连到tmp.u上也可能是挖井了
addedge(q,tmp.v);
}else{//tmp的端点v访问过了
vis[tmp.u]=1;
vissum++;
ans+=min(tmp.w,w[tmp.u]);//同理
addedge(q,tmp.u);
}
}
cout<<ans<<endl;
}
void addedge(priority_queue<Edge,vector<Edge>,cmp>& q,int x){//以点x为中心向外扩展边
for(int i=1;i<=n;i++){
if(i!=x){
q.push(Edge(x,g[x][i].end,g[x][i].w));
}
}
}