1.畅通工程
链接:https://vjudge.net/contest/351234#problem/H
题目描述:给出图,加最少的边把点全连起来。
题目分析:把连通的点看作一个整体,把它们连起来。
代码:
#include <stdio.h>
#include <stdlib.h>
int n,m,nm;
int b[1001],c[1001],d[1001],e[1000][1000];//b[]记各点的根
struct Way //c[]笔记是否已走
{ //d[]记a[]中各起点的头
int begin;
int end;
}a[1000000]; //存边
int comp(const void *p1,const void *p2)
{
if ((*(struct Way*)p2).begin>(*(struct Way*)p1).begin) return -1;
else return 1;
}
int dfs(int x,int y)
{
int i;
if(c[y]) return 0;
c[y]=1;
for(i=d[y];i<nm;i++)
{
if(a[i].begin!=y) break;
b[a[i].end]=x;
dfs(x,a[i].end);
}
return 0;
}
int main()
{
int i,j,p,w,u;
while(scanf("%d",&n)!=EOF&&n)
{ scanf("%d",&m);
for(i=1;i<=n;i++) //初始化
{
for(j=1;j<=n;j++)
{
e[i][j]=0;
}
}
for(i=0;i<m;i++) //这里复杂化了,没必要用图存边
{
scanf("%d%d",&w,&u);
e[w][u]=1;
e[u][w]=1;
}
for(i=1,w=0;i<=n;i++)
{
for(j=1;j<=n;j++)
{if(e[i][j]) {a[w].begin=i;a[w++].end=j;}}
}
nm=w;
qsort(a,nm,sizeof(a[0]),comp);
for(i=nm-1;i>=0;i--)
{
d[a[i].begin]=i;
}
for(i=1;i<=n;i++) b[i]=i;//初始化
for(i=1;i<=n;i++) c[i]=0;
for(i=1,p=0;i<=n;i++)
{
if(b[i]==i) {p++;dfs(i,i);} //根据根判断是否DFS标记
}
printf("%d\n",p-1);//根的数目-1就是需连的路
}
return 0;
}
2.还是畅通工程(点击下面链接)
链接:https://blog.csdn.net/jian_ke/article/details/104010893
3.畅通工程续
题目链接:https://vjudge.net/contest/351234#problem/J
题目描述:判断是否能到达终点,如果能算最短路。
模板题不分析
代码:
#include <stdio.h>
#include <stdlib.h>
int n,m,f,s;
int b[201],c[201],d[201];
struct Way
{
int begin;
int end;
int length;
}a[2002];
int comp(const void *p1,const void *p2)
{
if ((*(struct Way*)p2).begin>(*(struct Way*)p1).begin) return -1;
else return 1;
}
int dfs(int x)
{
int i;
c[x]=1;
for(i=d[x];i<2*m;i++)
{
if(a[i].begin!=x) break;
if(b[a[i].end]>b[a[i].begin]+a[i].length)
{b[a[i].end]=b[a[i].begin]+a[i].length;
if(c[a[i].end]==0&&a[i].end!=f) dfs(a[i].end);
}
}
c[x]=0;
return 0;
}
int main()
{
int i;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=0;i<2*m;i+=2)
{
scanf("%d%d%d",&a[i].begin,&a[i].end,&a[i].length);
a[i+1].begin=a[i].end;
a[i+1].end=a[i].begin;
a[i+1].length=a[i].length;
}
scanf("%d%d",&s,&f);
qsort(a,2*m,sizeof(a[0]),comp);
for(i=2*m-1;i>=0;i--)
{
d[a[i].begin]=i;
}
for(i=0;i<n;i++) b[i]=1e9;
b[s]=0;
dfs(s);
if(b[f]==1e9) printf("-1\n");
else printf("%d\n",b[f]);
}
return 0;
}
3.畅通工程再续
题目链接:https://vjudge.net/contest/351234#problem/K
题目分析:这是求MST问题,只不过边权需要计算和判断是否有效。
代码:
#include <stdio.h>
#include <algorithm>
#include <math.h>
using namespace std;
int g[105],h[105],n;//g[]标记根
double sum; //h[]标记树高
struct Way
{
int s,e;
double cost;
}a[10000];
bool com(const struct Way &p1,const struct Way &p2)
{
return p1.cost<p2.cost;
}
void chu() //初始函数
{
int i;
for(i=0;i<n;i++)
{
h[i]=0;
g[i]=i;
}
}
int fin(int x) //找根函数
{
if(g[x]==x) return x;
return g[x]=fin(g[x]);
}
void unit(int x,int y) //连接树的函数
{
x=fin(x);
y=fin(y);
if(h[x]>h[y]) g[y]=g[x];
else g[x]=g[y];
if(h[fin(x)]==h[fin(y)]) h[fin(x)]++;
}
int main()
{
int i,b[2][10000],j,y,x,k,t;//b[][]存点
double l;
scanf("%d",&t);
while(t--)
{ k=0,sum=0;
scanf("%d",&n);
chu();
for(i=0;i<n;i++)
{
scanf("%d%d",&b[0][i],&b[1][i]);
if(i>0)
{
for(j=0;j<i;j++)
{
x=b[0][i]-b[0][j];
y=b[1][i]-b[1][j];
l=x*x+y*y; //算边的平方
if(100<=l&&l<=1e6) //有效边存入
{
a[k].s=i;
a[k].e=j;
a[k++].cost=sqrt(l);
a[k].s=j;
a[k].e=i;
a[k].cost=a[k-1].cost;
k++;
}
}
}
}
sort(a,a+k,com);
for(i=0,j=1;i<k;i++)//找MSP
{
if(fin(a[i].s)!=fin(a[i].e))
{
sum+=a[i].cost;
unit(a[i].s,a[i].e);
j++;//记录连点数
}
}
if(j==n) printf("%.1lf\n",sum*100);
else printf("oh!\n");
}
}