第一次博客

10.26小测总结

话不多说,上题:
5、联络员(contact.cpp)
【题目描述】
Superoj 已经一岁了,网站也由最初的几个用户增加到了上万个用户,随着 Superoj
网站的逐步壮大,管理员的数目也越来越多,现在你身为Tyvj管理层的联络员,希望你找
到一些通信渠道,使得管理员两两都可以联络(直接或者是间接都可以)。Superoj 是一个
公益性的网站,没有过多的利润,所以你要尽可能的使费用少才可以。
目前你已经知道,Superoj 的通信渠道分为两大类,一类是必选通信渠道,无论价格
多少,你都需要把所有的都选择上;还有一类是选择性的通信渠道,你可以从中挑选一些
作为最终管理员联络的通信渠道。数据保证给出的通行渠道可以让所有的管理员联通。

【输入格式】
第一行 n,m 表示 Superoj 一共有 n 个管理员,有 m 个通信渠道。
第二行到 m+1 行,每行四个非负整数,p,u,v,w 当p=1时,表示这个通信渠道为必选
通信渠道;当p=2时,表示这个通信渠道为选择性通信渠道;u,v,w 表示本条信息描述的
是 u,v 管理员之间的通信渠道,u 可以收到 v 的信息,v 也可以收到 u 的信息,w 表
示费用。

【输出格式】
输出最小的通信费用。

【输入样例】
5 6
1 1 2 1
1 2 3 1
1 3 4 1
1 4 1 1
2 2 5 10
2 2 5 5

【输出样例】
9

题目解析

看到这道题,不难想到最小生成树。只需要将必选通讯通道先取出建立树后,选择性的通道就与普通模板无异了。题解代码方法为kruskal。

上代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,ans,cnt,father[2010];
struct node
{
	int u,v,w;
}e[10010];
bool cmp(node x,node y)
{
	return x.w<y.w;
}
int find(int x)
{
	if(x!=father[x])
	father[x]=find(father[x]);
	return father[x];
} 
void together(int x,int y)
{
	x=find(x);
	y=find(y);
	if(x!=y)father[x]=y;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	father[i]=i;
	int p,u,v,w;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d%d",&p,&u,&v,&w);
		if(p==1)
		{
			together(u,v);
			ans+=w;
		}
		else
		{
			e[++cnt].u=u;
			e[cnt].v=v;
			e[cnt].w=w;
		}
	}
	sort(e+1,e+cnt+1,cmp);
	for(int i=1;i<=cnt;i++)
	{
		int x=find(e[i].u);
		int y=find(e[i].v);
		if(x!=y)
		{
			together(x,y);
			ans+=e[i].w;
		}
	}
	cout<<ans;
}     

接下来是第6题
6、攻击路线(forest.cpp)
【题目描述】
经历千辛万苦,Tom终于来到了爱琳大陆的怪物森林。 怪物森林是一个N*M的矩阵,从上到下一共有N行,从左到右一共有M列。 对于每个位置(x,y)都有一个怪物,每个怪物都有一定的攻击力。 现在Tom想要从左上角(1,1)移动到右下角(N,M)。 Tom可以往上下左右四个方向移动,当然前提是不能移动出边界。 对于一条从(1,1)到(N,M)的移动路线,由于森林的特殊性,Tom只能选择该路线中攻击力最小的一个怪物进行攻击,并定义该怪物的攻击力为该路线的重要度。 现在Tom想要选择一条重要度最大的路线,请你回答Tom的询问。

【输入格式】
第一行有两个数N、M,表示森林的大小,用一个空格隔开。
接下来N行,每行M个数,第i+1行j列的数表示位置为(i,j)的怪物的攻击力。

【输出格式】
第一行输出一个数表示重要度最大的路线的重要度。

【样列输入】forest.in
2 2
7 5
3 4

【样列输出】forest.out
4

【样列解释】
选择(1,1)->(1,2)->(2,2)的路线可获得最大的重要度。

【数据规模】
对于20%的数据:1≤N,M≤10
对于70%的数据:1≤N,M≤500
对于100%的数据:1≤N,M≤800,所有怪物的攻击力在int范围内

题目解析

本题其实本来应该用最短路径SPFA,但因为数据原因,被卡了。
因此只能换个思路:二分答案加广搜。
由于上下限可以确定,所以我们可以用二分答案来逐步搜索。
方法:在最小最大限度的权值中取,中间值。用广搜来验证此值是否成立,如成立,则向右区间继续;不成立则反之。
上代码

#include <bits/stdc++.h> 
using namespace std; 
 
const int maxn=1005; 
int N,M; 
int A[maxn][maxn]; 
 
const int size=maxn*maxn; 
int q[size][2],head,tail; 
bool V[maxn][maxn]; 
 
inline void pb(int x,int y) 
{ 
  q[++tail][0]=x,q[tail][1]=y; 
  V[x][y]=true; 
} 
bool check(int x) 
{ 
  const int move[4][2]={{0,-1},{0,1},{1,0},{-1,0}}; 
  memset(V,0,sizeof(V)); 
  head=tail=0,pb(1,1); 
  while(head<tail) 
  { 
    int sx=q[++head][0],sy=q[head][1]; 
    for(int k=0;k<4;++k) 
    { 
      int tx=sx+move[k][0],ty=sy+move[k][1]; 
      if(tx<=0||ty<=0||tx>N||ty>M)continue; 
      if(V[tx][ty]||A[tx][ty]<x)continue; 
      pb(tx,ty); 
    } 
  } 
  return V[N][M]; 
} 
 
int main() 
{ 
  freopen("forest.in","r",stdin); 
  freopen("forest.out","w",stdout); 
   
  scanf("%d%d",&N,&M); 
  for(int i=1;i<=N;++i) 
  for(int j=1;j<=M;++j) 
    scanf("%d",&A[i][j]); 
   
  int lft=-1000000000,rgt=A[1][1],mid,ans; 
  while(lft<=rgt) 
  { 
    mid=lft+rgt>>1; 
    if(check(mid))ans=mid,lft=mid+1;else rgt=mid-1; 
  }   
  printf("%d\n",ans);  
  return 0; 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值