| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
用prim的wa可以看这里我开始的思路是这样的:用prim算法去求最小生成树,如果在求树的过程中出现了多重选择(就是说某一步可以被加入的节点有复数个),则认为图中的树不唯一。后来发现这个算法是有问题的。
一个例子:
1
4 3
1 2 1
1 3 1
1 4 1
这是一个爪子的形状,图本身就是一颗树。如果把节点1作为起始节点,第一步就会出现多重选择的情况,然而它的最小生成树是唯一的。
正确的算法是:先求出一颗最小生成树,然后每次去掉树上的一个边,重新求最小生成树。如果某次求出的权值和最初的一样,说明最小生成树是不唯一的,因为你求出了两颗不一样的最小生成树。
我求MST的算法是prim,prim的复杂度是O(n^2),最小生成树用n-1条边,所以最多要重新求n-1次最小生成树,所以整个算法的时间复杂度为O(n^3)。
代码写的很丑,拿出来望大家批评:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 105
#define INFINITY 2147483647
void prim1(int g[][MAX_SIZE],int n,int *vv,int edge[][3])
{
int low[MAX_SIZE][2],v,min,i,k,top;
char flag[MAX_SIZE];
memset(flag,0,n);
flag[0] = 1;
for(i=0;i<n;i++)
{
low[i][0] = g[0][i];
low[i][1] = 0;
}
v = 0;
top = 0;
for(k=1;k<n;k++)
{
//find min
for(i=0;i<n;i++)
if(!flag[i] && low[i][0]!=INFINITY)
break;
min = i;
for(i=i+1;i<n;i++)
if(!flag[i] && low[i][0]<low[min][0])
min = i;
//add min into mst
flag[min] = 1;
v += low[min][0];
edge[top][0] = low[min][1];
edge[top][1] = min;
edge[top][2] = low[min][0];
top++;
//fix low
for(i=0;i<n;i++)
if(!flag[i] && g[min][i]<low[i][0])
{
low[i][0] = g[min][i];
low[i][1] = min;
}
}
*vv = v;
}
void prim2(int g[][MAX_SIZE],int n,int *vv)
{
int low[MAX_SIZE],v,min,i,k;
char flag[MAX_SIZE];
memset(flag,0,n);
flag[0] = 1;
for(i=0;i<n;i++)
low[i] = g[0][i];
v = 0;
for(k=1;k<n;k++)
{
//find min
for(i=0;i<n;i++)
if(!flag[i] && low[i]!=INFINITY)
break;
min = i;
for(i=i+1;i<n;i++)
if(!flag[i] && low[i]<low[min])
min = i;
//add min into mst
flag[min] = 1;
v += low[min];
//fix low
for(i=0;i<n;i++)
if(g[min][i] < low[i])
low[i] = g[min][i];
}
*vv = v;
}
int main()
{
int T;
int n,m;
int i,j,k,w;
int g[MAX_SIZE][MAX_SIZE];
int v,vv;
int edge[MAX_SIZE][3];
scanf("%d",&T);
while(T>0)
{
//构建原始图
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
g[i][j] = INFINITY;
for(i=0;i<n;i++)
g[i][i] = 0;
for(k=0;k<m;k++)
{
scanf("%d%d%d",&i,&j,&w);
i--;
j--;
g[i][j] = w;
g[j][i] = w;
}
//用prim求出一棵树
prim1(g, n, &v, edge);
//依次去掉树中的边,重新求树,看求出来的权值是否相同
for(i=0;i<n-1;i++)
{
//去掉边
g[edge[i][0]][edge[i][1]] = INFINITY;
g[edge[i][1]][edge[i][0]] = INFINITY;
//重新求树
prim2(g, n, &vv);
if(v==vv)
break;
//回复图
g[edge[i][0]][edge[i][1]] = edge[i][2];
g[edge[i][1]][edge[i][0]] = edge[i][2];
}
if(i==n-1)
printf("%d\n",v);
else
printf("Not Unique!\n");
T--;
}
return 0;
}
Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator