IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 2017南宁(重温经典) -> 正文阅读

[数据结构与算法]2017南宁(重温经典)

2017南宁(重温经典)

导语

这场打的还可以,也学到了二分图的更简单的建图和匹配实现,虽然以前看过,但没有着重关注,这次直接整理了

涉及的知识点

二分图,模拟,递推

链接:训练赛 [Cloned]

题目

H

题目大意:略

思路:这道题给了一个启示,小的细节优化往往能带来出其不意的效果
思路是直接模拟暴力,但是如果直接从整个大平面空间逐个遍历显然是不合算的,可以发现,活着的细胞相比于整个平面空间都是少数,那么可以从这一部分入手,我们记录活着的人存在的区域,或者说涉及到的区域,每次对这个区域进行一次遍历,并判断是否产生了拓展,如果区域被拓展,那么更新即可,这样的总体复杂度会很低

代码

#include<bits/stdc++.h>
using namespace std;
int t,n,m;
int a[700][700],b[700][700];//相互作为临时数组
int getAround(bool flag,int x,int y) {//判断当前位置周围
    int sum=0;
    if(flag) {
        sum-=a[x][y];
        for(int i=-1; i<=1; i++)
            for(int j=-1; j<=1; j++)
                sum+=a[x+i][y+j];
    } else {
        sum-=b[x][y];
        for(int i=-1; i<=1; i++)
            for(int j=-1; j<=1; j++)
                sum+=b[x+i][y+j];
    }
    return sum;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >>t;
    while(t--) {
        cin >>n>>m;
        memset(a,0,sizeof(a));//初始化
        memset(b,0,sizeof(b));//同上
        char ch;
        int sum=0,mx=0,pos=0,d=350,u=350+5,l=350,r=350+5;
        //初始化边界
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++) {
                cin >>ch;
                if(ch=='#')
                    a[350+i][350+j]=1,sum++,mx++;
            }
        for(int i=1; i<=321; i++) {
            sum=0;
            if(i&1) {
                for(int i=d-1; i<=u+1; i++)//只判断涉及到的范围
                    for(int j=l-1; j<=r+1; j++) {
                        int res=getAround(1,i,j);
                        b[i][j]=a[i][j];
                        if((res<2||res>3)&&a[i][j])b[i][j]=0;
                        else if(res==3&&!a[i][j])b[i][j]=1;
                        sum+=b[i][j];
                        if(b[i][j]) {//如果可以拓展
                            if(i==d-1)d--;
                            else if(i==u+1)u++;
                            if(j==l-1)l--;
                            else if(j==r+1)r++;
                        }
                    }
            } else {
                for(int i=d-1; i<=u+1; i++)//只判断涉及到的范围
                    for(int j=l-1; j<=r+1; j++) {
                        int res=getAround(0,i,j);
                        a[i][j]=b[i][j];
                        if((res<2||res>3)&&b[i][j])a[i][j]=0;
                        else if(res==3&&!b[i][j])a[i][j]=1;
                        sum+=a[i][j];
                        if(a[i][j]) {
                            if(i==d-1)d--;
                            else if(i==u+1)u++;
                            if(j==l-1)l--;
                            else if(j==r+1)r++;
                        }
                    }
            }
            if(sum>mx)pos=i,mx=sum;
        }
        cout <<pos<<" "<<mx<<" "<<sum<<endl;
    }
    return 0;
}

I

题目大意:给出一共4×4矩阵,A和B对矩阵轮流操作,A先操作,每次操作选择一个2×2的矩阵,统计矩阵元素和加在总分数上,然后将这个2×2矩阵逆时针旋转90度,一共进行k轮,也就是2k次操作,A的目标是使得总分数最大,B的目标是使得总分数最小,计算两人在最优策略下最后获得的总分数

思路:直接暴力,可以计算出总时间复杂度由于数据范围很小

代码

#include<bits/stdc++.h>
using namespace std;
int t,n,m,k,a[12][12];
int getsum(int x,int y) {
    return a[x][y]+a[x+1][y]+a[x][y+1]+a[x+1][y+1];
}
void up(int x,int y) {
    int tmp=a[x][y];
    a[x][y]=a[x][y+1];
    a[x][y+1]=a[x+1][y+1];
    a[x+1][y+1]=a[x+1][y];
    a[x+1][y]=tmp;
}
void down(int x,int y) {
    int tmp=a[x][y];
    a[x][y]=a[x+1][y];
    a[x+1][y]=a[x+1][y+1];
    a[x+1][y+1]=a[x][y+1];
    a[x][y+1]=tmp;
}
int DFS(int level) {//参数为第level次操作
    if(level==2*k) {
        int mn=0x3f3f3f3f;
        for(int i=1; i<4; i++)
            for(int j=1; j<4; j++)
                mn=min(mn,getsum(i,j));
        return mn;
    }
    if(level&1) {//A操作
        int mx=0;
        for(int i=1; i<4; i++)
            for(int j=1; j<4; j++) {
                up(i,j);//操作
                int sum=getsum(i,j)+DFS(level+1);//遍历所有情况,直接看到最后一步
                mx=max(mx,sum);
                down(i,j);//还原
            }
        return mx;
    }
    int mn=0x3f3f3f3f;//B操作
    for(int i=1; i<4; i++)
        for(int j=1; j<4; j++) {
            up(i,j);
            int sum=getsum(i,j)+DFS(level+1);
            mn=min(mn,sum);
            down(i,j);
        }
    return mn;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >>t;
    while(t--) {
        cin >>k;
        for(int i=1; i<=4; i++)//录入矩阵
            for(int j=1; j<=4; j++)
                cin >>a[i][j];
        cout <<DFS(1)<<endl;
    }
    return 0;
}

M

题目大意:给出一共有向无环图 G G G,定义一个点集 V U R ? V V_UR?V VU?R?V作为 G G G的不可达集,集合中的任意两点 u , v u,v u,v两者间都不存在路径可到达彼此,求出 G G G的最大不可达集的大小

思路:很显然图被分成了两个集合,那么求的就是二分图的最大独立集,由于点很少,直接用矩阵存即可,跑最大匹配,最大独立集=总结点数-最大匹配

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
int n,m,match[121],res;
bool graph[121][121],vis[121];
bool maxmatch(int u) {
    for(int v=1; v<=n; v++) {//BFS
        if(!vis[v]&&graph[u][v]) {//如果没访问过
            vis[v]=1;
            if(match[v]==-1||maxmatch(match[v])) { //如果可以匹配
                match[v]=u;//设定匹配
                return 1;
            }
        }
    }
    return 0;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T;
    cin >>T;
    while(T--) {
        cin >>n>>m;
        memset(graph,0,sizeof(graph));
        while(m--) {
            int u,v;
            cin >>u>>v;
            graph[u][v]=1;
        }
        memset(match,-1,sizeof(match));
        res=0;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                for(int k=1; k<=n; k++)
                    graph[i][j]|=graph[i][k]&graph[k][j];
        for(int i=1; i<=n; i++) {
            memset(vis,0,sizeof(vis));
            if(maxmatch(i))res++;
        }
        cout <<n-res<<endl;
    }
    return 0;
}

L

题目大意:给出一个正整数 L L L,找到一个最小的不小于 L L L的整数 n n n,使得存在一个正整数 m m m满足等式 2 m ( m + 1 ) = n ( n + 1 ) 2m(m+1)=n(n+1) 2m(m+1)=n(n+1)

思路:首先数据量给的很大,因此线性遍历是不可能的,并且需要使用大数来进行存储与运算,因此使用Java语言,将等式中的 n n n视为已知,那么最后可以得到 m m m的表达式: 1 + 2 n 2 + 2 n / 2 ? 1 / 2 \sqrt{1+2n^2+2n}/2-1/2 1+2n2+2n ?/2?1/2,打表可以得到符合条件的 n n n的递推式: a [ i ] = ( a [ i ? 1 ] + a [ i ? 2 ] ) ? 5 + 4 ? a [ i ? 3 ] a[i]=(a[i-1]+a[i-2])*5+4-a[i-3] a[i]=(a[i?1]+a[i?2])?5+4?a[i?3]

代码

import java.math.BigInteger;
import java.util.Scanner;

public class Main {
	
	static BigInteger a[]= new BigInteger[2010];
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		init();
		Scanner inputScanner=new Scanner(System.in);
		int t = inputScanner.nextInt();
		for(int i = 1;i <= t;i++)
		{
			String string = inputScanner.next();
			BigInteger lBigInteger = new BigInteger(string);
			int l = 0;
			int r = 2000;
			if(lBigInteger.compareTo(a[l])<=0) {
				System.out.println(a[l].toString());
			}
			else {
				while(l<r)
				{
					int mid = (l+r)/2;
					if(a[mid].compareTo(lBigInteger)>=0)
					{
						r=mid;
					}
					else {
						l=mid+1;
					}
				}
				System.out.println(a[l].toString());
			}
		}
	}
	static void init() {
		a[0]=new BigInteger("3");
	    a[1]=new BigInteger("20");
	    a[2]=new BigInteger("119");
	    for(int i=3;i<=2000;i++)
	    {
	        a[i]=(a[i-1].add(a[i-2])).multiply(BigInteger.valueOf(5))
	        		.add(BigInteger.valueOf(4)).subtract(a[i-3]);
	    }
	}
}

参考文献

  1. icpc2017南宁H The Game of Life
  2. ACM 2017 南宁区域赛 Rake it in(对抗搜索)
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-11 22:26:29  更:2022-03-11 22:29:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 14:57:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码