和前一年那道暢通工程幾乎一模一樣,只要在加邊過程中增加在整個容器被遍歷結束時沒有加入頂點數-1條邊的判斷邏輯,此時無法判斷圖是否連通,意味着所有邊探查結束 所得不是一個連通分支:
克魯斯卡爾+並查集:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int part[100];
struct node//克魯斯卡爾算法是加邊法,使用node結構表示邊信息,而不是prim的數組
{
int from;
int to;
int cost;
};
vector<node> Vec;
int getFa(int n)
{
if(part[n]==n)return n;
part[n]=getFa(part[n]);
return part[n];
}
bool merge(int x,int y)
{
if(getFa(x)==getFa(y))return false;
part[getFa(y)]=x;return true;
}
bool cmp(node x,node y)
{
return x.cost<y.cost;
}
int main()
{
int n,m;//n爲邊數目,m爲頂點數目
while(cin>>n>>m&&n)
{
Vec.clear();
for (int i=1;i<=m;i++)part[i]=i;
int from,to,cost;
node temp;
while(n--)
{
cin>>from>>to>>cost;
temp.from=from;
temp.to=to;
temp.cost=cost;
Vec.push_back(temp);
}
sort(Vec.begin(),Vec.end(),cmp);//一開始傻到用vec作爲迭代器,汗
int count=m-1;
int sum=0;
for(vector<node>::iterator iter=Vec.begin();iter!=Vec.end();iter++)
if(merge(iter->from,iter->to))
{
sum+=iter->cost;
count--;
if(!count)break;
}
if(count)cout<<"?"<<endl;
else cout<<sum<<endl;
}
return 1;
}
普利姆算法: ps 搞不懂爲什麼用memset初始化是MAX值變爲了-1;
#include <iostream>
using namespace std;
#define MAX INT_MAX/2
int map[100][100];
int dist[10000];
void Prim(int m)
{
int sum=0;
int tag=1;//標示是否可連通
dist[1]=0;
for (int i=2;i<=m;i++)dist[i]=map[1][i];
for (int j=1;j<=m-1;j++)//依次加入剩餘n-1個頂點
{
int pos,temp=INT_MAX;
for (int k=2;k<=m;k++)
{
if (dist[k]<temp&&dist[k]>0)//如果使用<pos會出現未被賦值情況,加上等於沒有什麼影響 要不給temp賦更大的初值
{
temp=dist[k];
pos=k;
}
}
dist[pos]=0;
if (temp==MAX)
{
tag=0;break;
}
else sum+=temp;
for(int t=2;t<=m;t++)
{
if (dist[t]>map[pos][t])dist[t]=map[pos][t];
}
}
if(tag==0)cout<<"?"<<endl;
else cout<<sum<<endl;
}
int main()
{
int n,m;
while (cin>>n>>m&&n)
{
int from,to,length;
//memset(map,MAX,40000);//memset是處理一段連續的內存,以字節爲單位,第三個參數是字節數
for (int k=1;k<=m;k++)
for(int t=1;t<=m;t++)
map[k][t]=MAX;
for(int j=1;j<=m;j++)map[j][j]=0;
for(int i=1;i<=n;i++)
{
cin>>from>>to>>length;
map[from][to]=length;
map[to][from]=length;
}
Prim(m);
}
return 0;
}