入手的图论的第二题。这道题其实挺简单的,就是将已经有路的两个村庄之间的距离处理为0,然后用prim算法即可。
/*************************************************************************
> File Name: main.cpp
> Author:Eagles
> Mail:None
> Created Time: 2018年09月02日 星期日 22时30分07秒
> Description:HDU1102
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define N 101
int Grap[N][N];
int dis[N];
int vis[N];
int n;
const int INF=1<<30;
void init()
{
memset(vis,false,sizeof(vis));
memset(dis,0,sizeof(dis));
for (int i=0; i<n; i++)
{
for (int j=0; j<n ;j++)
{
scanf("%d",&Grap[i][j]);
}
}
int q;
scanf("%d",&q);
while (q--)
{
int a,b;
scanf("%d%d",&a,&b);
Grap[a-1][b-1]=Grap[b-1][a-1]=0;
}
for (int i=0; i<n; i++)
dis[i]=Grap[0][i];
vis[0]=true;
}
void print()
{
for (int i=0; i<n; i++)
printf("%d ",vis[i]);
printf("\n");
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j++)
{
printf("%d ",Grap[i][j]);
}
printf("\n");
}
}
void prim()
{
int sum=0;
for (int i=0; i<n-1; i++)
{
int minn=INF;
int tmp;
for (int j=0; j<n; j++)
{
if (!vis[j]&&dis[j]<minn)
{
minn=dis[j];
tmp=j;
}
}
vis[tmp]=true;
sum+=minn;
for (int j=0; j<n; j++)
{
if (!vis[j]&&Grap[tmp][j]<dis[j])
dis[j]=Grap[tmp][j];
}
}
printf("%d\n",sum);
}
int main()
{
while (~scanf("%d",&n))
{
init();
//print();
prim();
}
return 0;
}
但是这是我看了别人的题解之后做的。我原来可不是这样做的,所以一直WA,通过随机生成测试数据与别人程序对拍之后发现了问题所在。我原来的思路是:首先建立一个con[][]数组,用来保存已经有路连接的村庄,如果有路,con[i][j]=1,反之则为0.当处理完成后,由于我是选的第一个村庄作为prim算法的起始点,所以就将与第一个村庄相连的所有村庄加入到已经访问过的集合当中,但要注意的是,在加入的过程中要更新dis[]数组,即访问的集合到未访问的集合的各点的最小距离。怎样确定哪些村庄与第一个村庄相连呢?举个例子,比如1跟2相连,2跟3,4,6相连,那么1就跟2,3,4,6都相连,所以con[0][1],con[0][2],con[0][3],con[0][5]都应该为1.这里我用的是dfs来处理.原以为这样提交后可以AC,但是结果给我泼了一盆冷水。我苦思冥想了一个晚上,今天早上再测试了一下,才发现了问题所在:如果是1跟2相连,2跟3,4,6相连,那么比如5跟7相连但是不和1相连,那我上面的处理就没有利用到这一个语句,所以导致了错误。我在代码中改了一下,结果AC了,其实也就是如果相连,那么距离为0,跟别人的一样,但总算还是发现了错误。
WA,修改之后AC的代码:
/*************************************************************************
> File Name: main.cpp
> Author:Eagles
> Mail:None
> Created Time: 2018年09月02日 星期日 16时21分42秒
> Description:HDU1102
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int INF=1<<30;
#define N 101
int Gra[N][N];
int con[N][N];
bool vis[N];
int dis[N];
bool used[N];
int n;
void init()
{
memset(vis,false,sizeof(vis));
memset(con,0,sizeof(con));
memset(used,false,sizeof(used));
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j++)
{
scanf("%d",&Gra[i][j]);
if (i==j)
Gra[i][j]=0;
}
}
for (int i=0; i<n; i++)
dis[i]=Gra[0][i];
int q;
scanf("%d",&q);
while (q--)
{
int a,b;
scanf("%d%d",&a,&b);
con[a-1][b-1]=1;
con[b-1][a-1]=1;
}
}
void dfs(int i)
{
if (used[i])
return;
int flag=0;
for (int j=0; j<n; j++)
{
if (con[i][j])
{
flag=1;
}
}
if (flag==0)
return;
used[i]=true;
for (int j=1; j<n; j++)
{
if (con[i][j]==1)
{
con[0][j]=1;
dfs(j);
}
}
}
void ddfs(int i)//将不与第一个村庄相连,但是与其他相连的村庄的距离变为0
{
if (used[i])
return ;
used[i]=true;
for (int j=0; j<n; j++)
{
if (con[i][j]==1)
{
Gra[i][j]=Gra[j][i]=0;
ddfs(j);
}
}
}
void prim()
{
dfs(0);
con[0][0]=0;
for (int i=1; i<n; i++)//不与第一个相连,但是与其他相连,距离处理为0
{
if (con[0][i]==0)
ddfs(i);
}
vis[0]=true;
int cnt=1;
for (int i=0; i<n; i++)
{
if (con[0][i]==1)
{
cnt++;
vis[i]=true;
for (int j=0; j<n; j++)
{
if (!vis[j]&&Gra[i][j]<dis[j])
dis[j]=Gra[i][j];
}
}
}
int sum=0;
for (int i=0; i<n-cnt; i++)
{
int minn=INF;
int tmp;
for (int j=0; j<n; j++)
{
if (!vis[j]&&dis[j]<minn)
{
minn=dis[j];
tmp=j;
}
}
sum+=minn;
vis[tmp]=true;
//printf("sum:%d,tmp:%d\n",sum,tmp);
for (int j=0; j<n; j++)
{
if (!vis[j]&&Gra[tmp][j]<dis[j])
dis[j]=Gra[tmp][j];
}
}
printf("%d\n",sum);
}
void print()
{
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j++)
{
printf("%d ",Gra[i][j]);
}
printf("\n");
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while (~scanf("%d",&n))
{
init();
prim();
//print();
}
return 0;
}