

同样是一个最小生成树的题,不一样的是点与点之间可能有初始边,只需要关注添加的边,那么我们在一开始将其并集,在生成树的时候就会自动跳过,再用min,记录最小值,最后输出便可。
#include<stdio.h>
#include<math.h>
int tree[1005];
int find(int x)
{
if(tree[x]==x) return x;
else
{
tree[x]=find(tree[x]);
return tree[x];
}
}
void marge(int x,int y)
{
x=find(x);
y=find(y);
tree[x]=y;
}
struct b
{
int xx,yy;
double zz;
}a[500005];
void quick(int x,int y)
{
int i,j;
i=x;j=y;
double t=a[x].zz;
while(i<=j)
{
while(a[i].zz<t) i++;
while(a[j].zz>t) j--;
if(i<=j)
{
struct b m=a[i];
a[i]=a[j];
a[j]=m;
i++;
j--;
}
}
if(x<j) quick(x,j);
if(i<y) quick(i,y);
}
int main()
{
for(int i=1;i<=1001;i++) tree[i]=i;
long long s,p,x,y,num=0,num1=0,num2=0;
double l=0,min=0;
scanf("%lld %lld",&p,&s);
int bb[1005][2]={0},d[1005]={0};
struct b c[1005];
for(int i=1;i<=p;i++)
{
scanf("%lld %lld",&x,&y);
bb[i][0]=x;
bb[i][1]=y;
}
for(int i=1;i<=p-1;i++)
{
for(int j=i+1;j<=p;j++)
{
l=0;
num++;
a[num].xx=i;
a[num].yy=j;
x=bb[i][0]-bb[j][0];
y=bb[i][1]-bb[j][1];
l+=x*x+y*y;
l=sqrt(l);
a[num].zz=l;
}
}
quick(1,num);
for(int i=1;i<=s;i++)
{
scanf("%lld %lld",&x,&y);
marge(x,y);
}
for(int i=1;i<=num;i++)
{
if(find(a[i].xx)==find(a[i].yy)) continue;
marge(a[i].xx,a[i].yy);
num1+=1;
num2++;
c[num2].xx=a[i].xx;
c[num2].yy=a[i].yy;
c[num2].zz=a[i].zz;
min+=a[i].zz;
if(num1==p-1) break;
}
printf("%.2lf",min);
return 0;
}

dp题,用f[i]表示从起点到节点i的最短距离,每当发现更短距离,更新f[i],读完第一行时,更新n次,
读第二行时,第x个数表示节点2到节点x+2的距离,此时f[2]+x既节点1到节点x+2的新距离,如果这个数小于之前的最短距离即f[x+2],那么更新f[i],同理,读完n行后,f[n]为最短距离。
#include<stdio.h>
int main()
{
int f[201]={0},n,i,j,x;
scanf("%d",&n);
for (i=1;i<=n;i++)
for (j=i+1;j<=n;j++)
{
scanf("%d",&x);
if (f[j]==0||f[j]>f[i]+x)
f[j]=f[i]+x;
}
printf("%d\n",f[n]);
}