2.1总结

P2121 拆地毯

题目背景

还记得 NOIP 2011 提高组 Day1 中的铺地毯吗?时光飞逝,光阴荏苒,三年过去了。组织者精心准备的颁奖典礼早已结束,留下的则是被人们踩过的地毯。请你来解决类似于铺地毯的另一个问题。

题目描述

会场上有 n 个关键区域,不同的关键区域由 m 条无向地毯彼此连接。每条地毯可由三个整数 u、v、w 表示,其中 u 和 v 为地毯连接的两个关键区域编号,w 为这条地毯的美丽度。

由于颁奖典礼已经结束,铺过的地毯不得不拆除。为了贯彻勤俭节约的原则,组织者被要求只能保留 K 条地毯,且保留的地毯构成的图中,任意可互相到达的两点间只能有一种方式互相到达。换言之,组织者要求新图中不能有环。现在组织者求助你,想请你帮忙算出这 K 条地毯的美丽度之和最大为多少。

输入格式

第一行包含三个正整数 n、m、K。

接下来 m 行中每行包含三个正整数 u、v、w。

输出格式

只包含一个正整数,表示这 K 条地毯的美丽度之和的最大值。

输入输出样例

输入 #1

5 4 3

1 2 10

1 3 9

2 3 7

4 5 3

输出 #1

22

说明/提示

选择第 1、2、4 条地毯,美丽度之和为 10 + 9 + 3 = 22。

若选择第 1、2、3 条地毯,虽然美丽度之和可以达到 10 + 9 + 7 = 26,但这将导致关键区域 1、2、3 构成一个环,这是题目中不允许的。

1<=n,m,k<=100000

思路

和之前两个题目差不多的解决方法,只是它是求最大的权重值

代码如下:

#include<stdio.h>

int n,m,k;
int f[100005]={0},sum=0,count=0;
struct edge
{
    int u;
    int v;
    int w;
}e[100005];

void qsort(int left,int right)
{
    int i,j;
    struct edge t;
    if(left>right)
        return ;
    i=left;j=right;
    while(i!=j)
    {
        while(e[j].w>=e[left].w&&i<j)
            j--;
        while(e[i].w<=e[left].w&&i<j)
            i++;
        if(i<j)
        {
            t=e[i];
            e[i]=e[j];
            e[j]=t;
        }
    }
    t=e[left];
    e[left]=e[i];
    e[i]=t;
    qsort(left,i-1);
    qsort(i+1,right);
    return ;
}//快排

int getf(int v)
{
    if(f[v]==v)
        return v;
    else
    {
        f[v]=getf(f[v]);
        return f[v];
    }
}//并查集查找

int merge(int v,int u)
{
    int t1,t2;
    t1=getf(v);
    t2=getf(u);
    if(t1!=t2)
    {
        f[t2]=t1;
        return 1;
    }
    return 0;
}//并查集合并

int main()
{
    scanf("%d %d %d",&n,&m,&k);
    for(int i=1;i<=m;i++)
        scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
    qsort(1,m);
    for(int i=1;i<=n;i++)
        f[i]=i;
    for(int i=m;i>=1;i--)
    {
        if(merge(e[i].u,e[i].v))
        {
            count++;
            sum+=e[i].w;
        }
        if(count==k)
        break;
    }
    printf("%d",sum);
}

最小生成树

Prim算法

//最小生成树实现Prim算法
#include<stdio.h>
int main(){
    int i,j,n,m,k,min,t1,t2,t3;
    int e[7][7],dis[7],book[7]={0};//这里对book数组进行初始化 
    int inf=99999999;//存储一个我们认为的正无穷值
    int count=0,sum=0;// count 用来记录生成树中顶点的个数,sum用来存储路径之和
     
    //读入n和m,n表示顶点数目,m表示边的数目
    scanf("%d %d",&n,&m);
    
    //初始化
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            if(i==j) e[i][j]=0;
                else e[i][j]=inf;
            
    //读入边
    for(i=1;i<=m;i++)
    {
        scanf("%d %d %d",&t1,&t2,&t3);
        //注意这里是无向图,所以需要将边反向再存储一遍
        e[t1][t2]=t3;
        e[t2][t1]=t3;    
    } 
    
    //初始化dis数组,这里是1号顶点到各个顶点的初始距离,因为当前生成树中只有1号顶点
    for(i=1;i<=n;i++)
    { 
        dis[i]=e[1][i];
    } 
    
    //Prim算法核心代码
    //将1号顶点加入生成树 
    book[1]=1; //用book来标记一个点是否已经加入了生成树
    count++;
    while(count<n)
    {
        min=inf;
        for(i=1;i<=n;i++)
        {
            if(book[i]==0 && dis[i]<min)
                min=dis[i];
                j=i;    
        }
        book[j]=1;count++;sum=sum+dis[j];
        //扫描当前顶点j所有的边,再次以j为中间点,更新生成树到每一个非树顶点的距离
        for(k=1;k<=n;k++) 
        {
            if(book[k]==0 &&dis[k]>e[j][k])
                dis[k]=e[j][k];
        }
    } 
    
       printf("%d ",sum);
    
    getchar();
    getchar();
    return 0;
 
}

堆优化后的Prim算法

/*prim算法实现:使用邻接表来存储图并且使用堆优化*/

#include<stdio.h>
#define inf 999999;

int dis[7], book[7];// book数组用来记录哪些顶点已经放入生成树中
int h[7], pos[7]; //h用来保存堆,pos用来保存堆中每一个顶点的位置   
int size; //size用来表示堆的大小

void swap(int x,int y)
{
    int t = h[x];
    h[x] = h[y];
    h[y] = t;

    //同步更新pos
    t = pos[h[x]];
    pos[h[x]] = pos[h[y]];
    pos[h[y]] = t;
    return ;
}

//向下调整函数
void siftdown(int i)  //对堆中编号为i的节点实时向下调整
{
    int t, flag = 0;  //flag用来标记是否需要继续向下调整
    while (i*2<= size&&flag==0)  //左孩子存在 
    {
        if (dis[h[i]] > dis[h[2 * i]])
            t = i * 2;
        else
            t = i;

        //如果有右儿子急需判断

        if (i * 2 + 1 <= size)
        {
            if (dis[h[t]] > dis[i * 2 + 1])
                t = i * 2 + 1;
        }

        if (t != i)
        {
            swap(t, i);
            i = t;       //便于接下来继续向下调整
        }
        else
            flag = 1;//不在需要向下调整了
    }
    return ;
}

void siftup(int i)   //对编号i进行向上调整
{
    int flag = 0;
    if (i == 1)
        return;//在堆顶直接返回

    //不在堆顶并
    while (i != 1&&flag==0)
    {
        //与父节点进行比较
        if (dis[h[i / 2]] > dis[h[i]])
            swap(i, i / 2);
        else
            flag = 1;
        i = i / 2;   //更新节点方便下一次使用
    }
    return ;
}
void create() //创建一个堆
{
    //从最后一个非叶节点开始实行向下调整
    for (int i = h_size / 2; i >= 1; --i)
        siftdown(i);
}

//从堆顶中取出一个元素
int pop()
{
    int t = h[1];
    pos[t] = 0;
    h[1] = h[size];
    pos[h[1]] = 1;       //更新顶点h[1]在堆中的位置
    size--;
    siftdown(1);        //向下调整
    return t;
}
int main()
{
    int n, m;//顶点个数和边的个数

    int u[19], v[19], w[19]; //采用邻接矩阵来存储图 表示顶点u[i]到顶点v[i]的权重为w[i]  由于为无向图实际的大小为2*m+1
    int first[7];           //存储的是节点i的第一条边的编号为first[i],大小为n+1;
    int next[19];           //存储的是编号为i的边的下一条边的编号next[i]。

   scanf("%d %d",&n,&m);
    for (int i = 1; i <= m; ++i)
    {
        scanf("%d %d %d",&u[i],&v[i],&w[i]);
    }

    //由于为无向图所以还需要存储一遍
    for (int i = m + 1; i <= 2 * m; ++i)
    {
        u[i] = v[i - m];
        v[i] = u[i - m];
        w[i] = w[i - m];
    }

    //采用邻接表来存储图,首先对first数组初始化,最开始没有读入边 所以记录为-1;
    for (int i = 1; i <= n; ++i)
        first[i] = -1;

    for (int i = 1; i <= 2 * m; ++i)
    {
        next[i] = first[u[i]];
        first[u[i]] = i;
    }

    //prim算法核心
    int count = 0;
    int sum = 0;
    //1号顶点加入到生成树中
    book[1] = 1;
    count++;

    //初始化dis数组
    dis[1] = 0;
    for (int i = 2; i <= n; ++i)
        dis[i] = inf;
    int k = first[1];  //1号节点的第一条边的编号
    while (k!=-1)
    {
        dis[v[k]] = w[k];
        k = next[k];
    }

    //初始化堆
    size = n;
    for (int i = 1; i <= h_size; ++i)
    {
        h[i] = i;
        pos[i] = i;
    }
    create();
    pop();//先弹出堆顶元素 此时堆顶元素是一号顶点

    while (count<n)
    {
        //堆顶元素加入到生成树当中
        int j = pop();
        book[j] = 1;
        count++;
        sum += dis[j];

        //以j为中心对边进行松弛
        int k = first[j];
        while (k!=-1)
        {
            if (book[v[k]] == 0 && dis[v[k]] > w[k])
            {
                dis[v[k]] = w[k]; //更新距离
                siftup(pos[v[k]]);  //对该顶点在堆中的位置进行松弛,pos[i]中存放的是节点i在堆中的位置
            }
            k = next[k];
        }
    }
    printf("%d",sum);
    getchar();getchar();
    return 0;
}

P2872 [USACO07DEC]Building Roads S

题目描述

Farmer John had just acquired several new farms! He wants to connect the farms with roads so that he can travel from any farm to any other farm via a sequence of roads; roads already connect some of the farms.

Each of the N (1 ≤ N ≤ 1,000) farms (conveniently numbered 1..N) is represented by a position (Xi, Yi) on the plane (0 ≤ Xi ≤ 1,000,000; 0 ≤ Yi ≤ 1,000,000). Given the preexisting M roads (1 ≤ M ≤ 1,000) as pairs of connected farms, help Farmer John determine the smallest length of additional roads he must build to connect all his farms.

给定 n 个点的坐标,第 i 个点的坐标为 (xi,yi),这 n 个点编号为 11 到 n。给定 m 条边,第 i 条边连接第 ui 个点和第 vi 个点。现在要求你添加一些边,并且能使得任意一点都可以连通其他所有点。求添加的边的总长度的最小值。

输入格式

* Line 1: Two space-separated integers: N and M

* Lines 2..N+1: Two space-separated integers: Xi and Yi

* Lines N+2..N+M+2: Two space-separated integers: i and j, indicating that there is already a road connecting the farm i and farm j.

第一行两个整数 n,m 代表点数与边数。

接下来 n 行每行两个整数xi,yi 代表第 i 个点的坐标。

接下来 m 行每行两个整数ui,vi 代表第 i 条边连接第 ui 个点和第vi 个点。

输出格式

* Line 1: Smallest length of additional roads required to connect all farms, printed without rounding to two decimal places. Be sure to calculate distances as 64-bit floating point numbers.

一行一个实数代表添加的边的最小长度,要求保留两位小数,为了避免误差, 请用 6464 位实型变量进行计算。

输入输出样例

输入 #1

4 1

1 1

3 1

2 3

4 3

1 4

输出 #1

4.00

说明/提示

数据规模与约定

对于 100%100% 的整数,1≤n,m≤1000,1≤xi,yi≤10^6,1≤ui,vin

说明

Translated by 一只书虫仔。

思路

这个和上次哪个哨所的差不多,但是这场是指定好的哪些点之间已经有路了。不知道为什么题目给定的坐标明明是整形,需要改成double才能过,最好把所有长度相关的数据都改成double,不然就会一直wa😰

代码如下

#include<stdio.h>
#include<math.h>
int k=1;
double x[1005],y[1005];
int f[1005],count=0;
double sum=0;
struct edge
{
    int u;
    int v;
    double dis;
}e[2023010];

double coor(int i,int j)
{
    double z;
    z=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
    return z;
}//求点之间距离的平方

void qsort(int left,int right)
{
    int i,j;
    struct edge t;
    if(left>right)
        return ;
    i=left;j=right;
    while(i!=j)
    {
        while(e[j].dis>=e[left].dis&&i<j)
            j--;
        while(e[i].dis<=e[left].dis&&i<j)
            i++;
        if(i<j)
        {
            t=e[i];
            e[i]=e[j];
            e[j]=t;
        }
    }
    t=e[left];
    e[left]=e[i];
    e[i]=t;
    qsort(left,i-1);
    qsort(i+1,right);
    return ;
}//快排

int getf(int v)
{
    if(f[v]==v)
        return v;
    else
    {
        f[v]=getf(f[v]);
        return f[v];
    }
}//并查集查找

int merge(int v,int u)
{
    int t1,t2;
    t1=getf(v);
    t2=getf(u);
    if(t1!=t2)
    {
        f[t2]=t1;
        return 1;
    }
    return 0;
}//并查集合并

int main()
{
    int n,m,a,b;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%lf %lf",&x[i],&y[i]);
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
    {
        e[k].u=i;
        e[k].v=j;
        e[k].dis=coor(i,j);
        k++;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d",&a,&b);
       e[k].u=a;
       e[k].v=b;
       e[k].dis=0;
       k++;
    }
    qsort(1,k);
    for(int i=1;i<=n;i++)
        f[i]=i;
    for(int i=1;i<=k;i++)
    {
        if(merge(e[i].u,e[i].v))
        {
            count++;
            sum+=sqrt(e[i].dis);
        }
        if(count==n-1)
            break;
    }
    printf("%.2lf",sum);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TensorFlow是一个开源的机器学习框架,版本2.1是其中的一个版本。你可以使用命令行进入Python的交互式环境,并导入TensorFlow来查看其版本号:`python` -> `import tensorflow as tf` -> `tf.__version__`。 如果你需要安装TensorFlow 2.1,我建议使用镜像来加快下载速度,比如使用豆瓣源。你可以使用以下命令安装TensorFlow 2.1: `pip install tensorflow==2.1 -i https://pypi.douban.com/simple/`。 在TensorFlow中,如果你想要从外部传入数据,你可以使用`tf.placeholder()`来定义占位符,然后通过`sess.run()`函数传输数据,具体可以参考以下代码示例: ``` import tensorflow as tf tf.compat.v1.disable_eager_execution() input1 = tf.compat.v1.placeholder(tf.float32) input2 = tf.compat.v1.placeholder(tf.float32) output = tf.multiply(input1, input2) with tf.compat.v1.Session() as sess: print(sess.run(output, feed_dict={input1: [7.], input2: [2.]})) ``` 这段代码实现了两个数的乘法运算,其中`input1`和`input2`是占位符,通过`feed_dict`参数传入具体的值进行计算。 在TensorFlow中,你还可以使用激活函数(也称为激励函数)来引入非线性性质。常用的激活函数有ReLU、Sigmoid和Tanh等。你可以根据具体的需求选择不同的激活函数来改变神经网络的行为。 最后,TensorFlow中的Variable变量可以用于存储和更新模型的参数。你可以使用`tf.Variable()`来创建变量,并使用`assign()`等方法来更新变量的值。变量在训练过程中可以被不断地调整和优化,以适应模型的需求。 总结起来,TensorFlow 2.1是一个用于机器学习的开源框架,你可以使用命令行查看其版本号,安装它并使用各种功能,如占位符、激活函数和变量。希望这些信息能对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值