洛谷 P3366 【模板】最小生成樹(並查集+壓縮路徑(縮短到最高上一級的步驟))
菜鳥生成記(12)
話說這個演算法思想應該屬於K開頭的演算法吧;這個演算法還挺好的,比P開頭的那個演算法好理解;
我總以為我可以做一些不尋常的事(比如:在不瞭解兩種最小生成樹的演算法前,自己試圖寫一下,結果超時60%);菜鳥就是菜鳥,好好刷水題吧!
暴力解決不了任何問題,只能解決自己(暴力的思想要改改了)
AC程式碼後附有O(n^3)的程式碼;
#include<bits/stdc++.h>
using namespace std;
const int N=5e+3+10;//看準資料範圍,(我第一次提交時,RU了4個點;陣列開小了)
const int M=2e+5+10;
int pre[N]={0};
struct st{
int v1,v2;//兩個頂點
int w;//邊權
st(){v1=v1=w=0;}//初始化(在這一題沒什麼用,但是定義時初始化是個好習慣噢!)
}s[M];
int cmp(const st &a,const st &b)
{//sort的排序條件(比較權值決定傳值的兩個元素是否交換)
return a.w<b.w;
}
int find(int x)
{//找祖先
int t=x;
while(pre[t]!=t)//只有祖先元素的值是自己(主函式裡pre陣列初始化每個陣列元素都是自己的祖先)
{
t=pre[t];//迴圈前往上一輩
}
return t;//返回祖先
}
int main()
{
int n,m;//n:結點數 m:邊數
int sum=0;//最小代價計數
int k=0;//最小生成樹加入邊數計數(n-1)
//都一條邊就有環路,少一條就不連通
int x,y,w;
int t1,t2;
cin>>n>>m;
for(int i=1;i<=n;i++)//初始化
{//每個元素都是自己的祖先
pre[i]=i;
}
for(int i=0;i<m;i++)
{//記錄每條邊的兩個頂點和權值
cin>>x>>y>>w;
s[i].v1=x,s[i].v2=y;
s[i].w=w;
}
sort(s,s+m,cmp);//按權值從小到大排序
/*
從小到大排序後,迴圈時就可以優先選擇邊的權值小的邊;
然後迴圈中就不用考慮這個邊是否是可加入最小的邊;
只需要判斷加入這個邊是否會形成環路;
*/
for(int i=0;i<m;i++)
{
x=s[i].v1,y=s[i].v2;
w=s[i].w;
t1=find(x);//找祖先
t2=find(y);//找祖先
if(t1!=t2)//祖先不一樣(生成樹加入該邊不會構成環路)
{
k++;//生成樹邊數記錄
sum+=w;//生成樹權值累加
int f1,f2;
pre[y]=t1;//讓y認x的祖先為y的祖先
pre[t2]=t1;//讓y的祖先也認x的祖先為自己的祖先
/*
這就是壓縮路徑,使每個元素找到祖先(最上面的一級)的步驟減少;
但是這樣就找不到爸爸(離自己最近的上一級);因為所有元素都在儘可能
認祖先為爸爸,原來的爸爸就找不到了; 不過不影響這一的運作過程;
*/
if(k==n-1)//最小生成樹形成,迴圈結束
break;
}
else//祖先一樣,x,y屬於一棵樹(連通分支)
continue;
}
cout<<sum<<endl;
return 0;
}
暴力廣搜超時60%(O(n^3))
#include<bits/stdc++.h>
using namespace std;
typedef struct st ak;
const int N=5e+3+10;
const int M=2e+5+10;
int e[N][N]={0};//鄰接矩陣
struct st{
int v1,v2,w;
st(){v1=v2=w=0;}
}s[M];
int n;
int m;//結點數
int cmp(ak a,ak b)
{
return a.w<b.w;
}
int find(int x,int y)
{//廣搜從一個頂點出發
//從x出發能夠到達y,說明x,y在一個連通分量中,return 0;
//否則 return 1;
int q[N]={0};
int f=0,r=0;
int book[N]={0};
q[r++]=x;
book[x]=1;
while(f!=r)
{
int k=q[f++];
for(int i=1;i<=m;i++)
{
if(!book[i]&&e[k][i]!=0)
{
book[i]=1;
if(i==y)
return 0;
q[r++]=i;
}
}
}
return 1;
}
int main()
{
int sum=0;
int k=0;
cin>>m>>n;//m結點數,n邊數
for(int i=0;i<n;i++)
{
int x,y,w;
cin>>x>>y>>w;
s[i].v1=x,s[i].v2=y,s[i].w=w;
}
sort(s,s+n,cmp);//按權值從小到大排序
for(int i=0;i<n;i++)
{
int x,y,w;
x=s[i].v1,y=s[i].v2,w=s[i].w;
//printf("[%d,%d,%d]->\n",x,y,w);
if(x==y)//自環 跳過
continue;
if(find(x,y)==1)//判斷x,y是否在一個聯通分量中
{
e[x][y]=w;
e[y][x]=w;
sum+=w;
}
else//在一個連通分量中,重邊,選擇權值最小的,作為邊權
{//新權值小於原有權值
//更新x->y和y->x的權值
if(w<e[x][y])
{
sum-=e[x][y];
e[x][y]=e[y][x]=w;
sum+=w;
}
}
}
cout<<sum<<endl;
return 0;
}
/*
5 8
1 3 4
1 2 1
1 4 5
2 5 2
2 4 4
3 5 3
4 5 2
3 5 1
*/
/*
5 18
2 4 276
3 3 435
3 4 608
2 4 860
1 2 318
1 3 547
5 4 419
2 5 98
1 5 460
5 3 399
3 5 240
3 2 733
3 3 903
4 2 909
5 2 206
3 4 810
2 1 115
2 3 419
*/
相關文章
- 並查集系列之「路徑壓縮( path compression ) 」並查集路徑壓縮
- 為什麼並查集路徑壓縮時不需要維護rank?並查集路徑壓縮
- word文件太大怎麼壓縮到最小 word壓縮檔案大小
- Nginx網路壓縮 CSS壓縮 圖片壓縮 JSON壓縮NginxCSSJSON
- 洛谷:P2814 家譜(並查集)並查集
- 【模板】最小生成樹
- 洛谷 P6362 平面歐幾里得最小生成樹
- 【模板】最小生成樹-kruskal
- tar解壓到指定目錄並去掉壓縮檔案的層級資料夾
- 網址縮短 短網址連結縮短生成器的試用推薦
- 洛谷OJ:P2764 最小路徑覆蓋問題(網路流)
- 壓縮錶轉非壓縮表(線上重定義)
- 壓縮Word,一鍵實現Word文件壓縮
- 洛谷 P3919 可持久化線段樹 1 之主席樹模板(初級)持久化
- 【親媽教學】配置Gzip壓縮,含前後端步驟後端
- 檔案壓縮和解壓縮
- tinypng upload一鍵壓縮上傳工具
- Linux中檔案的壓縮和解壓縮Linux
- 目前網頁最小字型以及字型壓縮網頁
- java 生成 zip格式 壓縮檔案Java
- Python實現壓縮和解壓縮Python
- JS壓縮方法及批量壓縮JS
- linux下壓縮解壓縮命令Linux
- linux壓縮和解壓縮命令整理Linux
- 洛谷 - P3690 【模板】Link Cut Tree (動態樹)(LCT模板)
- 寫模板, 並查集。並查集
- 用ASP實現線上壓縮與解壓縮功能程式碼
- oracle壓縮表(一)Oracle
- ppt怎麼壓縮,ppt壓縮的技巧分享
- linux 高效壓縮工具之xz的壓縮解壓使用Linux
- 如何利用新浪官方的短網址API介面實現T.cn短連結的壓縮生成API
- Linux tar分卷壓縮與解壓縮Linux
- js上傳圖片壓縮JS
- 虛擬機器硬碟vmdk壓縮瘦身並掛載到VirtualBox虛擬機硬碟
- 並查集到帶權並查集並查集
- Linux 常用的壓縮與解壓縮命令詳解Linux
- Linux下的tar壓縮解壓縮命令詳解Linux
- 移動端使用localResizeIMG4壓縮圖片並上傳