题目地址:​​点击打开链接​

题意:给你一堆城市,然后来了一次海啸,海啸完了还有一些城市是连在一块的,问把所有的城市连在最小的花费是多少

思路:Kruskal算法超了无数发,后来改用prim算法,把海啸过后,连在一块的城市之间的距离设为0即可,用C++提交

AC代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>

using namespace std;

const int maxn = 510;
const int zui = 0x3f3f3f3f;
int lowdist[maxn];
int map1[maxn][maxn];
int visit[maxn];
int n,m,k,sum;
bool flag;

void Prim()
{
int i,j,k;
memset(visit,0,sizeof(visit));
for(i=1; i<=n; i++)
{
lowdist[i] = map1[1][i];
}
visit[1] = 1;
sum = 0;
for(i=1; i<n; i++)
{
int min1 = zui;
for(j=1; j<=n; j++)
{
if(!visit[j] && lowdist[j] < min1)
{
min1 = lowdist[j];
k = j;
}
}
if(min1 == zui)
{
flag = false;
return;
}
visit[k] = 1;
sum += lowdist[k];
for(j=1; j<=n; j++)
{
if(!visit[j] && map1[k][j] < lowdist[j])
{
lowdist[j] = map1[k][j];
}
}
}
}

int main()
{
int t;
int i,j;
scanf("%d",&t);
while(t--)
{
flag = true;
memset(map1,zui,sizeof(map1));
scanf("%d%d%d",&n,&m,&k);
int p,q,c;
for(i=1; i<=m; i++)
{
scanf("%d%d%d",&p,&q,&c);
if(c < map1[p][q])
{
map1[p][q] = map1[q][p] = c;
}
}
int l,temp,x;
for(i=1; i<=k; i++)
{
scanf("%d%d",&l,&temp);
for(j=1; j<l; j++)
{
scanf("%d",&x);
map1[temp][x] = map1[x][temp] = 0;
}
}
Prim();
if(flag)
{
printf("%d\n",sum);
}
else
{
printf("-1\n");
}
}
return 0;
}


AC代码2:该开始用G++投的T了,和代码1没啥区别就是初始化是用了循环语句,后来代码1用从C++过了,然后把这个代码也试着用C++投,也过了,不过时间比代码1长一点

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>

using namespace std;

const int maxn = 510;
const int zui = 1000000000;
int lowdist[maxn];
int map1[maxn][maxn];
int visit[maxn];
int n,m,k,sum;
bool flag;

void Prim()
{
int i,j,k;
memset(visit,0,sizeof(visit));
for(i=1; i<=n; i++)
{
lowdist[i] = map1[1][i];
}
visit[1] = 1;
sum = 0;
for(i=1; i<n; i++)
{
int min1 = zui;
for(j=1; j<=n; j++)
{
if(!visit[j] && lowdist[j] < min1)
{
min1 = lowdist[j];
k = j;
}
}
if(min1 == zui)
{
flag = false;
return;
}
visit[k] = 1;
sum += lowdist[k];
for(j=1; j<=n; j++)
{
if(!visit[j] && map1[k][j] < lowdist[j])
{
lowdist[j] = map1[k][j];
}
}
}
}

int main()
{
int t;
int i,j;
scanf("%d",&t);
while(t--)
{
flag = true;
scanf("%d%d%d",&n,&m,&k);
for(i=1; i<=n; i++)
{
for(j=1; j<=n; j++)
{
map1[i][j] = zui;
}
map1[i][i] = 0;
}
int p,q,c;
for(i=1; i<=m; i++)
{
scanf("%d%d%d",&p,&q,&c);
if(c < map1[p][q])
{
map1[p][q] = map1[q][p] = c;
}
}
int l,temp,x;
for(i=1; i<=k; i++)
{
scanf("%d%d",&l,&temp);
for(j=1; j<l; j++)
{
scanf("%d",&x);
map1[temp][x] = map1[x][temp] = 0;
}
}
Prim();
if(flag)
{
printf("%d\n",sum);
}
else
{
printf("-1\n");
}
}
return 0;
}

最后来点Kruskal的超时代码

超时代码1:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>

using namespace std;

const int maxn = 510;
const int zui = 1000000000;
int lowdist[maxn];
int map1[maxn][maxn];
int visit[maxn];
int n,m,k,sum;
bool flag;

void Prim()
{
int i,j,k;
memset(visit,0,sizeof(visit));
for(i=1; i<=n; i++)
{
lowdist[i] = map1[1][i];
}
visit[1] = 1;
sum = 0;
for(i=1; i<n; i++)
{
int min1 = zui;
for(j=1; j<=n; j++)
{
if(!visit[j] && lowdist[j] < min1)
{
min1 = lowdist[j];
k = j;
}
}
if(min1 == zui)
{
flag = false;
return;
}
visit[k] = 1;
sum += lowdist[k];
for(j=1; j<=n; j++)
{
if(!visit[j] && map1[k][j] < lowdist[j])
{
lowdist[j] = map1[k][j];
}
}
}
}

int main()
{
int t;
int i,j;
scanf("%d",&t);
while(t--)
{
flag = true;
scanf("%d%d%d",&n,&m,&k);
for(i=1; i<=n; i++)
{
for(j=1; j<=n; j++)
{
map1[i][j] = zui;
}
map1[i][i] = 0;
}
int p,q,c;
for(i=1; i<=m; i++)
{
scanf("%d%d%d",&p,&q,&c);
if(c < map1[p][q])
{
map1[p][q] = map1[q][p] = c;
}
}
int l,temp,x;
for(i=1; i<=k; i++)
{
scanf("%d%d",&l,&temp);
for(j=1; j<l; j++)
{
scanf("%d",&x);
map1[temp][x] = map1[x][temp] = 0;
}
}
Prim();
if(flag)
{
printf("%d\n",sum);
}
else
{
printf("-1\n");
}
}
return 0;
}


用k判环超时,改用n判环,里面少一个for循环,时间应该少很多

超时代码2:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>

using namespace std;

int pre[510];

struct node
{
int left,right,value;
}a[25010];

int cmp(const void *_a,const void *_b)
{
struct node *a = (node*)_a;
struct node *b = (node*)_b;
return a->value - b->value;
}

int findroot(int x)
{
return x == pre[x] ? x : pre[x] = findroot(pre[x]);//求根节点加路径压缩
}

int main()
{
int t,n,m,k;
int i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
for(i=1; i<=n; i++)
{
pre[i] = i;
}
for(i=0; i<m; i++)
{
scanf("%d%d%d",&a[i].left,&a[i].right,&a[i].value);
}
qsort(a,m,sizeof(node),cmp);
int sum,l,x;
int root1,root2;
for(i=0; i<k; i++)
{
scanf("%d",&sum);
scanf("%d",&l);
root1 = findroot(l);
for(j=1; j<sum; j++)
{
scanf("%d",&x);
root2 = findroot(x);
if(root1 != root2)
{
pre[root2] = pre[root1];
n--;
}
}
}
sum = 0;
for(i=0; i<m; i++)
{
root1 = findroot(a[i].left);
root2 = findroot(a[i].right);
if(root1 != root2)
{
sum += a[i].value;
pre[root1] = root2;
n--;
}
if(n == 1)
break;
}
if(n == 1)
{
printf("%d\n",sum);
}
else
{
printf("-1\n");
}
}
return 0;
}

用n判环依旧超

超时代码3:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>

using namespace std;

int pre[510];

struct node
{
int left,right,value;
}a[25010];

int cmp(const void *_a,const void *_b)
{
struct node *a = (node*)_a;
struct node *b = (node*)_b;
return a->value - b->value;
}

int findroot(int x)
{
return x == pre[x] ? x : pre[x] = findroot(pre[x]);//求根节点加路径压缩
}

int main()
{
int t,n,m,k;
int i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
for(i=1; i<=n; i++)
{
pre[i] = i;
}
for(i=0; i<m; i++)
{
scanf("%d%d%d",&a[i].left,&a[i].right,&a[i].value);
}
qsort(a,m,sizeof(node),cmp);
int sum,l,x;
int root1,root2;
for(i=0; i<k; i++)
{
scanf("%d",&sum);
scanf("%d",&l);
root1 = findroot(l);
for(j=1; j<sum; j++)
{
scanf("%d",&x);
root2 = findroot(x);
if(root1 != root2)
{
pre[root2] = pre[root1];
n--;
}
}
}
sum = 0;
for(i=0; i<m; i++)
{
if(pre[a[i].left] != pre[a[i].right])
{
pre[pre[a[i].left]] = pre[a[i].right];
sum += a[i].value;
n--;
}
if(n == 1)
break;
}
if(n == 1)
{
printf("%d\n",sum);
}
else
{
printf("-1\n");
}
}
return 0;
}

减少函数调用依旧超时