NOIP模拟赛4总结

我 自 闭 了
可 谓 惨 烈

这场比赛……不总结一下我良心上都过不去……

1.营救

题目描述

铁塔尼号遇险了!他发出了求救信号。距离最近的哥伦比亚号收到了讯息,时间就是生命,必须尽快赶到那里。
通过侦测,哥伦比亚号获取了一张海洋图。这张图将海洋部分分化成 n ∗ n n*n nn 个比较小的单位,其中用 1 1 1 标明的是陆地,用 0 0 0 标明是海洋。船只能从一个格子,移到相邻的四个格子。
为了尽快赶到出事地点,哥伦比亚号最少需要走多远的距离。

输入格式

第一行为 n n n,下面是一个 n ∗ n n*n nn 0 、 1 0、1 01 矩阵,表示海洋地图。
最后一行为四个小于 n n n 的整数,分别表示哥伦比亚号和铁塔尼号的位置。

输出格式

哥伦比亚号到铁塔尼号的最短距离,答案精确到整数。

样例
样例输入
3
001
101
100
1 1 3 3
样例输出
4
数据范围与提示

N ≤ 1000 N\le1000 N1000

思路

这种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 1n,其中有一些人相互认识,现在 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 nxy2n100; 接下来的 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了,尝试一下总是没问题的~

posted @ 2020-08-02 22:20  XSC062  阅读(120)  评论(0编辑  收藏  举报