pku 1861

pku 1861
最小生成树。不算难,可是由于太久没写了,而且Prim算法跟Dijkstra框架又差不多,导致错了几次:
1. Dijkstra每次找到离集合S最近的点v后,是一次Relax操作(见前面的单源最短路系列),而Prim只是简单地将较小的边权赋值给v,作为新的估计值。
2. 标准c++ 中int的存储位数为32位。
3. 使用memset要小心,对于int数组a来说,memset(a,k,sizeof(a)),当k=-1,0,1时可以用,但k不为以上值时,会出错,得用循环赋值。

另外最小生成树(MST)有以下重要性质:
Lemma : 对于所有生成树T来说,MST不但所有边权值之和最小,而且这些边权值的最大值在所有生成树中也是最小的。证明还没想好。迟些再补上。

#include  < iostream >
#include 
< list >
#define INF 
1000001

using namespace std;

const   int  maxn = 1001 ;

int  g[maxn][maxn];
long  close[maxn];
bool visit[maxn];
int  trace[maxn];     //  存储生成树
int  n,m;

void  prim()
{
    
//int total=0;
    int minedge=-1;
    
int i,j,k;
    memset(visit,
0,sizeof(visit));
    
for(i=1;i<n;i++) close[i]=1000001;
    memset(trace,
-1,sizeof(trace));
    visit[
0]=1;
    close[
0]=0;
    
for(i=1;i<n;i++)
    
{
        
if(g[0][i]>0)
        
{
            close[i]
=g[0][i];
            trace[i]
=0;
        }

    }

    
for(i=0;i<n-1;i++)
    
{
        
int index;
        
int mindis=1000001;
        
for(j=1;j<n;j++)
        
{
            
if(visit[j]==0 && close[j]<mindis)
            
{
                mindis
=close[j];
                index
=j;
            }

        }

        visit[index]
=1;
        minedge
=(close[index]>minedge)?close[index]:minedge;
        
for(j=1;j<n;j++)
        
{
            
if(g[index][j]>0 && visit[j]==0 && close[j]>g[index][j])
            
{
                close[j]
=g[index][j];
                trace[j]
=index;
            }

        }

    }

    printf(
"%d\n",minedge);
    printf(
"%d\n",n-1);
    
for(i=1;i<n;i++)
    
{
        
if(trace[i]!=-1) printf("%d %d\n",trace[i]+1,i+1);
    }

}


int  main()
{
    freopen(
"in.txt","r",stdin);
    memset(g,
0,sizeof(g));
    scanf(
"%d%d",&n,&m);
    
int i,j,k,w;
    
for(i=0;i<m;i++)
    
{
        scanf(
"%d%d%d",&j,&k,&w);
        g[j
-1][k-1]=g[k-1][j-1]=w;
    }

    prim();
    
return 1;
}

你可能感兴趣的:(pku 1861)