7.3图论模拟

FJSC图论测试

题目

1.无线通讯网(wireless.pas/cpp/c)

【题目描述】

国防部计划用无线网络连接若干个边防哨所。2种不同的通讯技术用来搭建无线网络;每个边防哨所都要配备无线电收发器;有一些哨所还可以增配卫星电话。

任意两个配备了一条卫星电话线路的哨所(两边都拥有卫星电话)均可以通话,无论他们相距多远。而只通过无线电收发器通话的哨所之间的距离不能超过D,这是受收发器的功率限制。收发器的功率越高,通话距离D会更远,但同时价格也会更贵。

收发器需要统一购买和安装,所以全部哨所只能选择安装一种型号的收发器。换句话说,每一对哨所之间的通话距离都是同一个D。

你的任务是确定收发器必须的最小通话距离D,使得每一对哨所之间至少有一条通话路径(直接的或者间接的)。

【输入格式】 wireless.in

第1行:2个整数S(1<=S<=100)和P(S<P<=500),S表示可安装的卫星电话的哨所数,P表示边防哨所的数量。

接下里P行,每行描述一个哨所的平面坐标(x,y),以km为单位,整数,0<=x,y<=10000。

【输出格式】 wireless.out

第1行:1个实数D,表示无线电收发器的最小传输距离。精确到小数点后两位。

【样例输入】

2 4

0 100

0 300

0 600

150 750

【样例输出】

212.13

数据范围

对于20%的数据  P=2,S=1

对于另外20%的数据  P=4,S=2

对于100%的数据  1<=S<=100,S<P<=500

/*
"你的任务是确定收发器必须的最小通话距离D,
使得每一对哨所之间至少有一条通话路径
(直接的或者间接的)。"
恩 这句话要好好理解 反正我已开始是理解错了
第一遍用floyed跑了跑
D不是1-n的dis 而是1-n的路径上的所有边的最大值
这样的话 我们要求出可以连通所有点的一条路径
再用卫星电话删掉大的
看上去很明显了 最小生成树 显然Kruskal更适合
因为他就是按边的权值从小到大 借助并茶几
这恰好利于我们计算卫星电话的个数
下面是wa的代码
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 510
using namespace std;
int m,n,k,p;
bool f[maxn];
double x[maxn],y[maxn],g[maxn][maxn];
struct node
{
    double dis;
    int s,t;
}e[maxn*maxn];
int cmp(const node &a,const node &b)
{
    return a.dis>b.dis;
}
double Get_dis(int i,int j)
{
    return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
void floyed()
{
    for(int k=1;k<=n;k++)
      for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
          g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
}
int main()
{
    scanf("%d%d",&m,&n);
    for(int i=1;i<=n;i++)
      cin>>x[i]>>y[i];
    for(int i=1;i<=n;i++)
      for(int j=i+1;j<=n;j++)
        g[i][j]=Get_dis(i,j);
    floyed();
    for(int i=1;i<=n;i++)
      for(int j=i+1;j<=n;j++)
        {
          e[++k].dis=g[i][j];
          e[k].s=i;e[k].t=j;
        }
    sort(e+1,e+1+k,cmp);p=1;
    for(int i=1;i<=n&&m;i++)
      {
          int si=e[i].s,ti=e[i].t;
          if(!f[si])f[si]=1,m--;
          if(m==0)break;
          if(!f[ti])f[ti]=1,m--,p=i;
      }
    printf("%.2f\n",e[p].dis);
    return 0;
}
/*这是Ac的代码*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 510
using namespace std;
int m,n,k,p,tot,fa[maxn];
bool f[maxn];
double x[maxn],y[maxn],g[maxn][maxn];
struct node
{
    double dis;
    int s,t;
}e[maxn*maxn];
int cmp(const node &a,const node &b)
{
    return a.dis<b.dis;
}
double Get_dis(int i,int j)
{
    return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
int find(int x)
{
    if(x!=fa[x])fa[x]=find(fa[x]);
    return fa[x];
}
int main()
{
    //freopen("wireless.in","r",stdin);
    //freopen("wireless.out","w",stdout);
    scanf("%d%d",&m,&n);
    for(int i=1;i<=n;i++)
      cin>>x[i]>>y[i],fa[i]=i;
    for(int i=1;i<=n;i++)
      for(int j=i+1;j<=n;j++)
        {
          e[++k].dis=Get_dis(i,j);
          e[k].s=i;e[k].t=j;
        }
    sort(e+1,e+1+k,cmp);
    for(int i=1;i<=k;i++)
      {
          int r1=find(e[i].s);
          int r2=find(e[i].t);
          if(r1!=r2)
            {
                tot++;fa[r2]=r1;
          }
        if(tot+m>=n)
          {
              p=i;break;
          }
      }
    printf("%.2f\n",e[p].dis);
    return 0;
}

2.混合图(dizzy.pas/cpp/c)

【题目描述】

Hzwer神犇最近又征服了一个国家,然后接下来却也遇见了一个难题。

Hzwer的国家有n个点,m条边,而作为国王,他十分喜欢游览自己的国家。他一般会从任意一个点出发,随便找边走,沿途欣赏路上的美景。但是我们的Hzwer是一个奇怪的人,他不喜欢走到自己以前走过的地方,他的国家本来有p1条有向边,p2条无向边,由于国王奇怪的爱好,他觉得整改所有无向边,使得他们变成有向边,要求整改完以后保证他的国家不可能出现从某个地点出发顺着路走一圈又回来的情况。(注:m=p1+p2.)

概述:给你一张混合图,要求你为无向图定向,使得图上没有环。

【输入格式】 dizzy.in

第一行3个整数 n,p1,p2,分别表示点数,有向边的数量,无向边的数量。

第二行起输入p1行,每行2个整数 a,b 表示a到b有一条有向边。

接下来输入p2行,每行2个整数 a,b 表示a和b中间有一条无向边。

【输出格式】 dizzy.out

对于每条无向边,我们要求按输入顺序输出你定向的结果,也就是如果你输出a b,那表示你将a和b中间的无向边定向为a->b。

注意,也许存在很多可行的解。你只要输出其中任意一个就好。

【样例输入】

4 2 3

1 2

4 3

1 3

4 2

3 2

【样例输出】

1 3

4 2

2 3

数据范围

对于20%的数据 n<=10 p1<=10 p2<=5

对于30%的数据 n<=10 p1<=30 p2<=20

对于100%的数据 n<=100000 p1<=100000 p2<=100000

数据保证至少有一种可行解。

/*
这题实在没啥办法了 - -
暴力的话也就得10分(2^n)
直接看了题解 但还是不明白
先按又向边拓扑排序 然后按照拓扑序
处理每一条无向边 方向是从拓扑序小的指向大的
(以下纯属扯淡 只是个人想法)
其实最开始接触的拓扑排序就是用来判断有没有环的
有向无环图里的拓扑序总的趋势就是小的指向大的
如果我们确定无向边的方向的时候由大的指向小的
那显然就构造了一个环 既然题目保证有解 我们不妨这样连
每一条都避免成环
(好吧说不下去了 如果有神犇明白了 请留言 )
*/
#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
#define maxn 200010
using namespace std;
int n,p1,p2,head[maxn],num,q[maxn],k,ru[maxn],order[maxn];
stack<int>s;
struct node
{
    int u,v,pre;
}e[maxn];
void Add(int from,int to)
{
    num++;e[num].u=from;e[num].v=to;
    e[num].pre=head[from];head[from]=num;
}
void topsort()
{
    for(int i=1;i<=n;i++)
      if(ru[i]==0)s.push(i),q[++k]=i;
    while(!s.empty())
      {
          int p=s.top();s.pop();
          for(int i=head[p];i;i=e[i].pre)
            {
                ru[e[i].v]--;
                if(ru[e[i].v]==0)q[++k]=e[i].v,s.push(e[i].v);
          }
      }
}
int main()
{
    //freopen("dizzy.in","r",stdin);
    //freopen("dizzy.out","w",stdout);
    scanf("%d%d%d",&n,&p1,&p2);
    int u,v;
    for(int i=1;i<=p1;i++)
      {
          scanf("%d%d",&u,&v);
          Add(u,v);ru[v]++;
      }
    topsort();
    for(int i=1;i<=n;i++)
      order[q[i]]=i;
    for(int i=1;i<=p2;i++)
      {
          scanf("%d%d",&u,&v);
          if(order[u]>order[v])printf("%d %d\n",v,u);
          else printf("%d %d\n",u,v);
      }
    return 0;
}

3.小K的农场(farm.pas/cpp/c)

【题目描述】

小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述:农场a比农场b至少多种植了c个单位的作物,农场a比农场b至多多种植了c个单位的作物,农场a与农场b种植的作物数一样多。但是,由于小K的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。

【输入格式】 farm.in

第一行包括两个整数n和m,分别表示农场数目和小K记忆中的信息数目。

接下来m行:

如果每行的第一个数是1,接下来有3个整数a,b,c,表示农场a比农场b至少多种植了c个单位的作物。

如果每行的第一个数是2,接下来有3个整数a,b,c,表示农场a比农场b至多多种植了c个单位的作物。

如果每行第一个数是3,家下来有2个整数a,b,表示农场a终止的数量和b一样多。

【输出格式】 farm.out

如果存在某种情况与小K的记忆吻合,输出“Yes”,否则输出“No”。

【样例输入】

3 3

3 1 2

1 1 3 1

2 2 3 2

【样例输出】

Yes

样例解释:三个农场种植数量可以为(2,2,1)。

对于100%的数据  1<=n,m,a,b,c<=10000.

/*
这题一看就是查分约束 然而我似乎还是不理解这个东西
自己敲了一下发现不对 算了 先慢慢理解一下这个东西吧
注意 下面的代码是Wa的
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 10010
using namespace std;
int n,m,head[maxn],num,dis[maxn];
struct node
{
    int u,v,t,pre;
}e[maxn];
bool f[maxn];
queue<int>q;
void Add(int from,int to,int dis)
{
    num++;e[num].u=from;e[num].v=to;e[num].t=dis;
    e[num].pre=head[from];head[from]=num;
}
void SPFA()
{
    memset(dis,128,sizeof(dis));
    f[1]=1;q.push(1);dis[1]=0;
    while(!q.empty())
      {
          int k=q.front();q.pop();
          for(int i=head[k];i;i=e[i].pre)
            {
                dis[e[i].v]=max(dis[e[i].v],dis[k]+e[i].t);
                if(f[e[i].v]==0)
                  {
                      f[e[i].v]=1;
                      q.push(e[i].v);
              }
          }
      }
}
int main()
{
    freopen("farm.in","r",stdin);
    freopen("farm.out","w",stdout);
    scanf("%d%d",&n,&m);
    int a,x,y,z;
    for(int i=1;i<=m;i++)
      {
          scanf("%d",&a);
          if(a==1)scanf("%d%d%d",&x,&y,&z),Add(x,y,z);
          if(a==2)scanf("%d%d%d",&x,&y,&z),Add(y,x,-z);
          if(a==3)scanf("%d%d",&x,&y),Add(x,y,0);
      }
    SPFA();
    if(dis[n]>=0)printf("Yes\n");
    else printf("No\n");
}
时间: 2024-10-16 22:58:38

7.3图论模拟的相关文章

多第八田间学校:几何+图论出度+模拟+找到规律

HDU 4946 pid=1002&cid=509" style="color:rgb(26,92,200); text-decoration:none; font-family:Tahoma; background-color:rgb(215,235,255)">Area of Mushroom 这题WA了7发才过,队友做的,然后一起debug了好久. 刚開始是没排序. 然后是在同一个位置的点没有处理好. 然后把这两个问题搞定就A了. #include <

模拟考试:图论专场

Phone [问题描述] 由于地震使得连接汶川县城电话线全部损坏,假如你是负责将电话线接到震中汶川县城的负责人,汶川县城周围分布着N(1 <= N <= 1,000)根按1..N顺次编号的废弃的电话线杆,任意两根电话线杆间都没有电话线相连.一共P(1 <= P <= 10,000)对电话线杆间可以拉电话线,其余的那些由于地震使得电线杆已经倒塌而无法被连接. 第i对电话线杆的两个端点分别为Ai.Bi,它们间的距离为Li (1 <= Li <= 1,000,000).数据中

[CSP-S模拟测试]:Graph(图论+贪心)

题目描述 给定一张$n$个点$m$条边的无向图,每条边连接两个顶点,保证无重边自环,不保证连通你想在这张图上进行若干次旅游,每次旅游可以任选一个点$x$作为起点,再走到一个与 $x$直接有边相连的点$y$,再走到一个与$y$直接有边相连的点$z$并结束本次旅游 作为一个旅游爱好者,你不希望经过任意一条边超过一次,注意一条边不能即正向走一次又反向走一次,注意点可以经过多次,在满足此条件下,你希望进行尽可能多次的旅游,请计算出最多能进行的旅游次数并输出任意一种方案 输入格式 第$1$行两个正整数$n

[CSP-S模拟测试]:木叶下(图论)

题目传送门(内部题77) 输入格式 第一行一个整数$n$,表示原先的树的点数接下来$n-1$行每行两个整数$a,b$,表示原先的树上的$n-1$条边,保证这$n-1$条边形成一棵树. 接下来一行一个整数$m$,表示不同的方案数. 接下来$m$行每行两个整数$u,v$,表示$m$个不同的加边方案,每行的方案表示在那一行给出的$u,v$之间加一条边.注意如果$u=v$,说明加了一条自环导致加边失败,此时最后留下$0$个点. 输出格式 $m$行,第$i$行一个整数表示第$i$次询问的答案. 样例 见下

图论及其应用——图

我们探索某个领域的知识,无不怀揣的核弹级的好奇心与求知欲,那么,今天,我们就将开始对图论的探索.   观察一副<机械迷城> 的一处谜题.    不得不承认,<机械迷城>这款解密游戏难度远胜于<纪念碑谷>, 其中一个困难点就在于——<纪念碑谷>的目标是很明确的,但是<机械迷城>往往需要自己凭感觉设立目标.而这里的关卡的目标,就是堵住第三个出水口. 为了解决这个谜题,如果不去考虑用暴力枚举的方法去试探(其实很多情况下都是用到这种情况)一开始,我们似乎

图论及其应用——树

在之前初步介绍图的文章中,我们得知,图(graph)是表征事物之间关系的一种抽象化表示方法,而基于图的概念,我们将所有的无回路无向图拿出来,给它们一个新的名字——树.  关于树的概念性术语很多,这里我们先就简单的二叉树(一个根至多有两个子树)来进行分析.    这就是一些简单的二叉树,这里A.B.C等我们成为节点.A叫做根节点,它的两个分支是B和C,并且我们称B是一个左子树,C是一个右子树,知道了这些简单的概念,我们就可以初步的探讨一些问题了. 二叉树树作为一种特殊的图,我们也要研究其遍历的方式

图论算法 有图有代码 万字总结 向前辈致敬

图的定义 背景知识 看到这篇博客相信一开始映入读者眼帘的就是下面这幅图了,这就是传说中的七桥问题(哥尼斯堡桥问题).在哥尼斯堡,普雷格尔河环绕着奈佛夫岛(图中的A岛).这条河将陆地分成了下面4个区域,该处还有着7座连接这些陆地的桥梁. 问题是如何从某地出发,依次沿着各个桥,必须经过每座桥且每座桥只能经过1次,最终回到原地. 不知道这个问题且好奇的童鞋现在肯定在忙活着找出来这道题的结果了. 是伟大的数学家欧拉(Leonhard Euler)在1736年首次使用图的方法解决了该问题. 欧拉将上面的模

第九章:图论和网络爬虫

上面我们谈了在搜索引擎中,如何建立索引,这里,我们讲如何自动下载互联网上所有的网页,重点就是图论中的遍历算法. 1.图论和网络爬虫 遍历算法主要有两种,一种是深度优先遍历,一种是广度优先遍历.所谓深度优先遍历,就是从一个节点开始,一直沿着一条路走到底,直到没路了,再回过头去找别的路,再一路走到底.说白了,就是往深处走.同样的,广度优先遍历,顾名思义,就是从一个节点开始,先把和他相连的都走一边,然后再以走过的节点为中心,一层一层走.拿网页来说,深度优先遍历,就是打开一个网页,选择其中一个URL,再

2017清北学堂集训笔记——图论

我们进入一个新的模块——图论! emmmmm这个专题更出来可能有点慢别介意,原因是要划的图和要给代码加的注释比较多,更重要的就是...这几个晚上我在追剧!!我们的少年时代超级超级超级好看,剧情很燃啊!!咳咳,好吧下面回归正题. 一.图的存储: 1.邻接矩阵: 假设有n个节点,建立一个n×n的矩阵,第i号节点能到达第j号节点就将[i][j]标记为1(有权值标记为权值), 样例如下图: 1 /*无向图,无权值*/ 2 int a[MAXN][MAXN];//邻接矩阵 3 int x,y;//两座城市