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;
}