题目貌似出的有点问题,考试的时候理解有点偏差。题干里说的是无向边,然而样例里Wij != Wji。晕了。以为是最小树形图。
最后和AC同学打听了一下,直接按无向边做就好了,其余的不用管。还有一定要加的那个边的方向不要边。
剩下就是标准的kruskal算法了。先把边按升序排序,再利用并查集向一个集合里加。如果没有冲突(要加的边的两点还没有再一个集合里,那么把这条边的两点相连,权值加入答案)。处理必须要加入的边,先把它的权值加入答案,再把这条边的权值修改为0,排序后,这条边一定会被选中。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=10010;
int n,m,f[N];
struct edge
{
int x,y;
int w;
}e[N];
bool cmp(const edge a,const edge b)
{
return a.w<b.w;
}
int root(int x)
{
if(f[x]==x) return x;
f[x]=root(f[x]);
return f[x];
}
void work()
{
int i,j,k,t,sum,ans;
int u,v;
sum=0;
m=0;
memset(e,0,sizeof(e));
for(i=0;i<=n;i++) f[i]=i;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&e[m].w);
e[m].x=i;
e[m].y=j;
if(i==j) e[m].w=100000000;
m++;
}
scanf("%d%d",&u,&v);
sum=e[(u-1)*n+v-1].w;
e[(u-1)*n+v-1].w=0;
sort(e,e+m,cmp);
for(i=0;i<m;i++)
{
j=root(e[i].x);
k=root(e[i].y);
if(j!=k)
{
f[j]=k;
sum+=e[i].w;
}
}
printf("%d\n",sum);
}
int main()
{
while(scanf("%d",&n)!=EOF)
work();
return 0;
}