zoukankan      html  css  js  c++  java
  • 洛谷P1331 海战 题解

    题目传送门

    思路

    肯定食用dfs啦。。。

    但关键是两条船接触了怎么判断呢??

    上图:

    可以发现一下规律

    当两条船接触时,必有一条直线连续穿过两条船

    当一条船不与另一条船接触时,没有一条直线连续穿过两条船

    所以只需要在每一次碰见一条船的一部分(一条船内每个点都要拓展一遍)时,将其沿右上、左下分别拓展一遍,边拓展边用sum前缀和check一遍就好啦。。。。

    核心代码:

    //码风很丑,勿喷
    int k=1;
    while(a[i+k][j+k]==1) k++;//找到最左下的一个点(即连线段的另一个端点)
    --k;//别忘了再加回来
    int hh=sum[i+k][j+k]-sum[i-1][j]-sum[i][j-1]+sum[i-1][j-1];//前缀和
    ++k;
    if(hh<k*k){//前缀和必须是k*k(一个正方形)
    	puts("Bad placement.");
    	return 0;//强制结束
    }//沿右上
    k=1;//清零
    while(a[i+k][j-k]==1) ++k;//找到最左下的一个点(即连线段的另一个端点)
    --k;
    hh=sum[i+k][j]-sum[i-1][j]-sum[i+k][j-k-1]+sum[i-1][j-k-1];//前缀和
    ++k;//别忘了再加回来
    if(hh<k*k){//前缀和必须是k*k(一个正方形)
    	puts("Bad placement.");
    	return 0;//强制结束
    }//沿左下
    

    如果没有接触的话,可以直接dfs啦。。。代码简洁:

    void dfs(int x,int y){
    	if(vis[x][y]==1) return ;//如果已经拓展过直接退出
    	vis[x][y]=1;//标记
    	if(a[x][y+1]==1) dfs(x,y+1);//向四个方向拓展,标记为此船
    	if(a[x-1][y]==1) dfs(x-1,y);
    	if(a[x+1][y]==1) dfs(x+1,y);
    	if(a[x][y-1]==1) dfs(x,y-1);
    }
    

    所有代码:(非常“简洁”。。。)

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	int ret=0,f=1;char ch=getchar();
    	while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();}
    	while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
    	return ret*f;
    }//丑陋的读优
    void write(int x){
    	if(x<0){
    		putchar('-');
    		write(-x);
    		return ;
    	}
    	if(x<10) putchar(x+'0');
    	else{
    		write(x/10);
    		putchar(x%10+'0');
    	}
    }//丑陋的输优
    int n,m,a[1010][1010],sum[1010][1010];
    int vis[1010][1010],ans;
    void dfs(int x,int y){
    	if(vis[x][y]==1) return ;
    	vis[x][y]=1;
    	if(a[x][y+1]==1) dfs(x,y+1);
    	if(a[x-1][y]==1) dfs(x-1,y);
    	if(a[x+1][y]==1) dfs(x+1,y);
    	if(a[x][y-1]==1) dfs(x,y-1);
    }//丑陋的dfs
    int main(){
    	n=read();m=read();
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			char ch;cin>>ch;
    			if(ch=='#') a[i][j]=1;
    		}
    	}//读入
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
    		}
    	}//前缀和
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			if(a[i][j]==1){
    				int k=1;
    				while(a[i+k][j+k]==1) k++;
    				--k;
    				int hh=sum[i+k][j+k]-sum[i-1][j]-sum[i][j-1]+sum[i-1][j-1];
    				++k;
    				if(hh<k*k){
    					puts("Bad placement.");
    					return 0;
    				}
    				k=1;
    				while(a[i+k][j-k]==1) ++k;
    				--k;
    				hh=sum[i+k][j]-sum[i-1][j]-sum[i+k][j-k-1]+sum[i-1][j-k-1];
    				++k;
    				if(hh<k*k){
    					puts("Bad placement.");
    					return 0;
    				}
    			}//不想再提了。。。判断船只是否接触
    		}
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			if(a[i][j]==1&&vis[i][j]==0){
    				++ans;
    				dfs(i,j);
    			}//dfs统计答案
    		}
    	}
    	cout<<"There are ";
    	write(ans);
    	cout<<" ships.";putchar('
    ');//输出
    	return 0;//结束。。。。
    }
    /*************************
    用时: 102ms / 内存: 5152KB
    代码:1.63KB C++
    By yuzhengxi
    **************************/
    
  • 相关阅读:
    TP框架对数据库的操作
    Nginx的安装及配置
    微信小程序的入门
    MySQL的多表联查
    Larave中CSRF攻击
    Linux(三)
    Linux(二)
    Linux(一)
    安全测试检查项
    mysql-视图及索引简介
  • 原文地址:https://www.cnblogs.com/yzx1798106406/p/10123174.html
Copyright © 2011-2022 走看看