NOIP模拟赛4总结
我 自 闭 了
这场比赛……不总结一下我良心上都过不去……
1.营救
题目描述
铁塔尼号遇险了!他发出了求救信号。距离最近的哥伦比亚号收到了讯息,时间就是生命,必须尽快赶到那里。
通过侦测,哥伦比亚号获取了一张海洋图。这张图将海洋部分分化成
n
∗
n
n*n
n∗n 个比较小的单位,其中用
1
1
1 标明的是陆地,用
0
0
0 标明是海洋。船只能从一个格子,移到相邻的四个格子。
为了尽快赶到出事地点,哥伦比亚号最少需要走多远的距离。
输入格式
第一行为
n
n
n,下面是一个
n
∗
n
n*n
n∗n 的
0
、
1
0、1
0、1 矩阵,表示海洋地图。
最后一行为四个小于
n
n
n 的整数,分别表示哥伦比亚号和铁塔尼号的位置。
输出格式
哥伦比亚号到铁塔尼号的最短距离,答案精确到整数。
样例
样例输入
3
001
101
100
1 1 3 3
样例输出
4
数据范围与提示
N ≤ 1000 N\le1000 N≤1000
思路
这种water题你还想要思路???
Code
一个简简单单的bfs能被我打RE,我也是佩服我自己了。。。
#include<queue>
#include<cstdio>
#include<cstdlib>
using std::queue;
struct zb{
int x,y,v;
}b,e;
queue<zb>q;
char a[1005][1005];
bool vis[1005][1005];
int n,x1,y1,x2,y2,ans;
int fangx[6]={0,0,1,-1};
int fangy[6]={1,-1,0,0};
void bfs(void){
zb f,nzb;
while(q.size()){
f=q.front();
q.pop();
if(f.x==e.x&&f.y==e.y){
printf("%d",f.v);
exit(0);
}
for(int i=0;i<4;++i){
nzb.x=f.x+fangx[i];
nzb.y=f.y+fangy[i];
nzb.v=f.v+1;
//↓我就是在这里没判断nzb.x和nzb.y会越界的情况,把!='0'写成了=='1'
if(a[nzb.x][nzb.y]!='0')
continue;
if(vis[nzb.x][nzb.y])
continue;
vis[nzb.x][nzb.y]=1;
q.push(nzb);
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%s",a[i]+1);
scanf("%d%d%d%d",&b.x,&b.y,&e.x,&e.y);
b.v=0;
vis[b.x][b.y]=1;
q.push(b);
bfs();
return 0;
}
2.关系网络
题目描述
有 n n n 个人,他们的编号为 1 ∼ n 1\sim n 1∼n,其中有一些人相互认识,现在 x x x 想要认识 y y y,可以通过他所认识的人来认识更多的人(如果 a a a 认识 b b b, b b b 认识 c c c,那么 a a a 可以通过 b b b 来认识 c c c),求出 x x x 最少需要通过多少人才能认识 y y y。
输入格式
第 1 1 1 行 3 3 3 个整数 n 、 x 、 y , 2 ≤ n ≤ 100 n、x、y,2\le n\le100 n、x、y,2≤n≤100; 接下来的 n n n 行是一个 n × n n×n n×n 的邻接矩阵, a [ i ] [ j ] = 1 a[i][j]=1 a[i][j]=1 表示 i 认识 j, a [ i ] [ j ] = 0 a[i][j]=0 a[i][j]=0 表示不认识。 保证 i = j i=j i=j 时, a [ i ] [ j ] = 0 a[i][j]=0 a[i][j]=0,并且 a [ i ] [ j ] = a [ j ] [ i ] a[i][j]=a[j][i] a[i][j]=a[j][i]。
输出格式
一行一个整数,表示 x x x 认识 y y y 最少需要通过的人数。数据保证 x x x 一定能认识 y y y。
样例
输入样例
5 1 5
0 1 0 0 0
1 0 1 1 0
0 1 0 1 0
0 1 1 0 1
0 0 0 1 0
输出样例
2
思路
很简单的最短路,可以用 D i j k s t r a Dijkstra Dijkstra。
Code
#include<vector>
#include<cstdio>
using namespace std;
bool vis[105];
vector<int>g[105];
int n,x,y,dis[105],num;
void add(int x,int y){
g[x].push_back(y);
g[y].push_back(x);
return;
}
void Dijkstra(void){
dis[x]=0;
for(int i=1;i<=n;++i){
int k=0;
for(int j=1;j<=n;++j){
if(dis[j]<dis[k]&&!vis[j])
k=j;
}
vis[k]=1;
int size=g[k].size();
for(int j=0;j<size;++j){
if(dis[k]+1<dis[g[k][j]])
dis[g[k][j]]=dis[k]+1;
}
}
return;
}
int main(){
scanf("%d%d%d",&n,&x,&y);
for(int i=0;i<=n;++i)
dis[i]=0x3f3f3f3f;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
scanf("%d",&num);
if(num)add(i,j);
}
}
Dijkstra();
printf("%d",dis[y]-1);
return 0;
}
3.「NOIP2014」寻找道路
题目在上面链接里~
一道比较烧脑的题,我一开始连题都没看懂,还一直以为样例有问题。。。(话说即使如此我也得了20分真是个奇迹)
题目大意就是从
s
s
s 到
t
t
t 的最短路,中间经过的每一个点和这个点的出边所连接的点都可以到达
t
t
t 。
#include<queue>
#include<cstdio>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxm=2*1e5+10,maxn=1e4+5;
queue<int>q;
int n,m,cnt,s,t;
int h[maxn],dis[maxn];
bool vis1[maxn],vis2[maxn],vis3[maxn];
struct Edge1{
int b,e,w;
Edge1(){}
Edge1(int B,int E,int W){
b=B,e=E,w=W;
}
}edge1[maxm];
struct Edge2{
int e,n,w;
Edge2(){}
Edge2(int E,int N,int W){
e=E,n=N,w=W;
}
}edge2[maxm];
void add(int b,int e,int w){
edge2[cnt]=Edge2(e,h[b],w);
h[b]=cnt++;
}
void work(int b){
vis3[b]=1;
for(int i=h[b];i!=-1;i=edge2[i].n){
int e=edge2[i].e;
if(!vis3[e])work(e);
}
return;
}
void es(int b){
vis1[b]=1;
bool f=1;
for(int i=h[b];i!=-1;i=edge2[i].n){
int e=edge2[i].e;
if(!vis3[e])f=0;
if(!vis1[e])es(e);
}
vis2[b]=f;
}
void Dijkstra(void){
q.push(s);
vis1[s]=1;
dis[s]=0;
while(!q.empty()){
int f=q.front();
q.pop();
vis1[f]=0;
for(int i=h[f];i!=-1;i=edge2[i].n){
int e=edge2[i].e;
if(!vis2[e])continue;
if(dis[e]>dis[f]+edge2[i].w){
dis[e]=dis[f]+edge2[i].w;
if(vis1[e])continue;
vis1[e]=1;
q.push(e);
}
}
}
return;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)h[i]=-1;
for(int i=1;i<=m;++i){
scanf("%d%d",&edge1[i].b,&edge1[i].e);
if(edge1[i].b==edge1[i].e)continue;
add(edge1[i].e,edge1[i].b,1);
}
scanf("%d%d",&s,&t);
work(t);
for(int i=1;i<=n;++i){
h[i]=-1;
dis[i]=inf;
}
cnt=0;
for(int i=1;i<=m;++i)
add(edge1[i].b,edge1[i].e,1);
for(int i=1;i<=n;++i)
if(!vis1[i])es(i);
for(int i=1;i<=n;++i)vis1[i]=0;
Dijkstra();
if(dis[t]==inf)printf("-1");
else printf("%d",dis[t]);
return 0;
}
我(哔——)!我居然看了题解才做出来这道题!嗯,一定是题太难了,不怪伦家。
4.「NOIP2010」引水入城
搜索,两个dfs可以解决(不要注意那些沙雕函数名与变量名)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[505][505],vis[505][505],v1s[505][505];
int fangx[5]={0,0,1,-1},fangy[5]={1,-1,0,0};
int n,m,mx,xxxx,ans;
void dfss(int x,int y){
int i,nx,ny;
v1s[x][y]=xxxx;
if(x==1)mx=max(y,mx);
for(i=0;i<4;++i){
nx=x+fangx[i],ny=y+fangy[i];
if(x<=0||x>n||y<=0||y>m)continue;
if(a[nx][ny]<=a[x][y]||v1s[nx][ny]==xxxx)
continue;
dfss(nx,ny);
}
}
void ddfs(int x,int y){
int i,nx,ny;
vis[x][y]=1;
for(i=0;i<4;++i){
nx=x+fangx[i],ny=y+fangy[i];
if(x<=0||x>n||y<=0||y>m)continue;
if(a[nx][ny]>=a[x][y]||vis[nx][ny])
continue;
ddfs(nx,ny);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j)
scanf("%d",&a[i][j]);
}
for(int i=1;i<=m;++i){
if(!vis[n][i]){
ans++,xxxx++;
mx=0;
dfss(n,i);
if(!mx){
ans=0;
for(int j=1;j<=m;++j)ddfs(1,j);
for(int j=1;j<=m;++j){
if(!vis[n][j])
ans++;
}
printf("0\n%d",ans);
return 0;
}
ddfs(1,mx);
}
}
printf("1\n%d",ans);
}
5.「一本通 3.2 练习 3」最短路计数
原本思路
用dfs的思想,用一个queue存放点,设队头点距离1的最短路为d,若这个点相邻点与1的距离恰好是d+1,就可以入队。
实际思路
不用那么复杂,在Dijkstra内完成,若可以进行松弛,更新答案。
Code
不!!!我居然TLE60???我左边那小屁孩连Dijkstra都没写都得了60!!!我不服!!!
#include <queue>
#include <vector>
#include <cstdio>
using namespace std;
const int maxn = 1000005;
typedef pair<int, int> pr;
bool vis[maxn];
vector<int> g[maxn];
int n, m, x, y, dis[maxn], num[maxn];
priority_queue<pr, vector<pr>, greater<pr> > q;
int read(void) {
char ch = 0;
int x = 0, f = 1;
while (ch < '0' || ch > '9') {
ch = getchar();
if (ch == '-') {
f = -1;
break;
}
}
while (ch <= '9' && ch >= '0') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
void add(int x, int y) {
g[x].push_back(y);
g[y].push_back(x);
return;
}
void Dijkstra(void) {
dis[1] = 0;
num[1] = 1;
q.push(make_pair(0, 1));
while (!q.empty()) {
int f = q.top().second;
q.pop();
if (vis[f])
continue;
vis[f] = 1;
int sz = g[f].size();
for (int i = 0; i < sz; ++i) {
int b = g[f][i];
if (dis[b] > dis[f] + 1) {
dis[b] = dis[f] + 1;
num[b] = num[f];
q.push(make_pair(dis[b], b));
} else if (dis[b] == dis[f] + 1)
num[b] = (num[b] + num[f]) % 100003;
}
}
}
int main() {
n = read();
m = read();
for (int i = 0; i <= n; ++i) dis[i] = 0x3f3f3f3f;
for (int i = 1; i <= m; ++i) {
x = read();
y = read();
add(x, y);
}
Dijkstra();
for (int i = 1; i <= n; ++i) printf("%d\n", num[i]);
return 0;
}
为什么你们看了那么久发现我只用Dijkstra呢?很简单,因为我只会Dijkstra呀!
为什么你们看了那么久发现我只有这题用了快读呢?很简单,因为这道题TLE了,尝试一下总是没问题的~
—— · EOF · ——
真的什么也不剩啦 😖