您的位置:首页 > 其它

poj 最小生成树入门水题 1251 && 1258 && 1287 && 2395 && 2485 && 2377

2016-09-13 22:33 357 查看
1251:

裸最小生成树

#include<iostream>//660k 0ms
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<limits.h>
using namespace std;
const int maxe=20010;
const int maxv=1009;

struct edge{
int u,v,w;
}es[maxe];

bool cmp(edge a,edge b){
return a.w<b.w;
}

int v,e;
int par[maxv];
int rank[maxv];

void init(int n){
for(int i=0;i<n;++i){
par[i]=i;
rank[i]=0;
}
}

int find(int x){
int r=x,temp;
while(r!=par[r]) r=par[r];
while(x!=r){//非递归路径压缩
temp=par[x];
par[x]=r;
x=temp;
}
return r;
}

void unite(int x,int y){
x=find(x);
y=find(y);
if(x==y) return;
if(rank[x]<rank[y]) par[x]=y;
else{
par[y]=x;
if(rank[x]==rank[y]) rank[x]++;
}
}

bool same(int x,int y){
return find(x)==find(y);
}

int kruskal(){
sort(es,es+e,cmp);
init(v);
int res=0,sumv=0;
for(int i=0;i<e;++i){
edge e=es[i];
if(sumv>=v-1) break;
if(!same(e.u,e.v)){
unite(e.u,e.v);
++sumv;
res+=e.w;
}
}
return res;
}

int main(){
int n,te;
char c[2];//chars c; 会报错.... 使用 char c[2] + c[0] 代替
while(scanf("%d",&v),v){
e=0;
for(int i=0;i<v-1;++i){
scanf("%s%d",c,&n);//<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">或者scanf(" %c %d",&c,&n);+char c;</span>
if(n==0) continue;
else{
for(int j=0;j<n;++j){
scanf("%s%d",c,&te);
es[e].u=i;
es[e].v=c[0]-'A';
es[e++].w=te;
}
}
}
printf("%d\n",kruskal());
}
return 0;
}


1258:

同上

#include<stdio.h>//708k 16ms
#include<iostream>
#include<math.h>
#include<algorithm>
#include<string.h>
using namespace std;
#define maxv 110
#define inf 99999999

int v,cost[maxv][maxv],mincost[maxv];
bool used[maxv];

int prim(){
for(int i=0;i<v;++i){
mincost[i]=inf;
used[i]=0;
}
mincost[0]=0;
int res=0;
while(1){
int j=-1;
for(int i=0;i<v;++i){
if(!used[i]&&(mincost[i]<mincost[j]||j==-1)) j=i;
}
if(j==-1) break;
used[j]=1;
res+=mincost[j];
for(int i=0;i<v;++i){
mincost[i]=min(mincost[i],cost[j][i]);
}
}
return res;
}

int main(){
while(~scanf("%d",&v)){
for(int i=0;i<v;++i){
for(int j=0;j<v;++j)
scanf("%d",&cost[i][j]);
}
printf("%d\n",prim());
}
return 0;
}


1287:

注意输入有多重边,只需保留最小权值。

#include<stdio.h>//676k 16ms
#include<iostream>
#include<math.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxv=60;
const int inf=9999999;

int v,e,cost[maxv][maxv],mincost[maxv];
bool used[maxv];

int prim(){
for(int i=1;i<=v;++i){
mincost[i]=inf;
used[i]=0;
}
mincost[1]=0;
int res=0;
while(1){
int j=-1;
for(int i=1;i<=v;++i){
if(!used[i]&&(mincost[i]<mincost[j]||j==-1)) j=i;
}
if(j==-1) break;
used[j]=1;
res+=mincost[j];
for(int i=1;i<=v;++i){
mincost[i]=min(mincost[i],cost[j][i]);
}
}
return res;
}

int main(){
int a,b,c;
while(~scanf("%d",&v),v){
scanf("%d",&e);
if(!e) puts("0");
else{
for(int i=0;i<maxv;++i){
for(int j=0;j<maxv;++j){
cost[i][j]=inf;
}
}
for(int i=1;i<=e;++i){
scanf("%d%d%d",&a,&b,&c);
cost[a][b]=cost[b][a]=min(cost[a][b],c);
}
printf("%d\n",prim());
}
}
return 0;
}


2395:

输出最小生成树中的最长边

对kruskal算法略作修改,res由记录最小权值和改为记录最长边即可

#include<iostream>//792k 47ms
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<limits.h>
using namespace std;
const int maxe=10010;
const int maxv=2009;

struct edge{
int u,v,w;
}es[maxe];

bool cmp(edge a,edge b){
return a.w<b.w;
}

int v,e;
int par[maxv];
int rank[maxv];

void init(int n){
for(int i=0;i<n;++i){
par[i]=i;
rank[i]=0;
}
}

int find(int x){
int r=x,temp;
while(r!=par[r]) r=par[r];
while(x!=r){//非递归路径压缩
temp=par[x];
par[x]=r;
x=temp;
}
return r;
}

void unite(int x,int y){
x=find(x);
y=find(y);
if(x==y) return;
if(rank[x]<rank[y]) par[x]=y;
else{
par[y]=x;
if(rank[x]==rank[y]) rank[x]++;
}
}

bool same(int x,int y){
return find(x)==find(y);
}

int kruskal(){
sort(es,es+e,cmp);
init(v);
int res=0,sumv=0;
for(int i=0;i<e;++i){
edge e=es[i];
if(sumv>=v-1) break;
if(!same(e.u,e.v)){
unite(e.u,e.v);
++sumv;
res=max(res,e.w);
}
}
return res;
}

int main(){
int a,b,c;
while(~scanf("%d%d",&v,&e)){
for(int i=0;i<e;++i){
es[i].w=INT_MAX;
scanf("%d%d%d",&a,&b,&c);
es[i].u=a;
es[i].v=b;
es[i].w=min(es[i].w,c);
}
printf("%d\n",kruskal());
}
return 0;
}


2485:

同上。采用prim算法,172ms.....

#include<stdio.h>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<string.h>
using namespace std;
#define maxv 520
#define inf 99999999

int v,cost[maxv][maxv],mincost[maxv];
bool used[maxv];

int prim(){
for(int i=0;i<v;++i){
mincost[i]=inf;
used[i]=0;
}
mincost[0]=0;
int res=0;
while(1){
int j=-1;
for(int i=0;i<v;++i){
if(!used[i]&&(mincost[i]<mincost[j]||j==-1)) j=i;
}
if(j==-1) break;
used[j]=1;
res=max(res,mincost[j]);
//		res+=mincost[j];
for(int i=0;i<v;++i){
mincost[i]=min(mincost[i],cost[j][i]);
}
}
return res;
}

int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&v);
for(int i=0;i<v;++i){
for(int j=0;j<v;++j)
scanf("%d",&cost[i][j]);
}
printf("%d\n",prim());
}
return 0;
}


2377:

稍作变形。最大生成树,若不能建树,输出-1。

#include<iostream>//1196B 16ms
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<limits.h>
using namespace std;
const int maxe=20010;
const int maxv=1009;

struct edge{
int u,v,w;
}es[maxe];

bool cmp(edge a,edge b){
return a.w>b.w;
}

int v,e;
int par[maxv];
int rank[maxv];

void init(int n){
for(int i=0;i<n;++i){
par[i]=i;
rank[i]=0;
}
}

int find(int x){
int r=x,temp;
while(r!=par[r]) r=par[r];
while(x!=r){//非递归路径压缩
temp=par[x];
par[x]=r;
x=temp;
}
return r;
}

void unite(int x,int y){
x=find(x);
y=find(y);
if(x==y) return;
if(rank[x]<rank[y]) par[x]=y;
else{
par[y]=x;
if(rank[x]==rank[y]) rank[x]++;
}
}

bool same(int x,int y){
return find(x)==find(y);
}

int kruskal(){
sort(es,es+e,cmp);
init(v);
int res=0,sumv=0;
for(int i=0;i<e;++i){
edge e=es[i];
if(sumv>=v-1) break;
if(!same(e.u,e.v)){
unite(e.u,e.v);
++sumv;
res+=e.w;
}
}
if(sumv<v-1) res=-1;
return res;
}

int main(){
int a,b,c;
while(~scanf("%d%d",&v,&e)){
for(int i=0;i<e;++i){
es[i].w=INT_MIN;
scanf("%d%d%d",&a,&b,&c);
es[i].u=a;
es[i].v=b;
es[i].w=max(es[i].w,c);
}
printf("%d\n",kruskal());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: